##// END OF EJS Templates
configurable locking codes....
marcink -
r3522:7174ee85 beta
parent child Browse files
Show More
@@ -1,449 +1,454 b''
1 ################################################################################
1 ################################################################################
2 ################################################################################
2 ################################################################################
3 # RhodeCode - Pylons environment configuration #
3 # RhodeCode - Pylons environment configuration #
4 # #
4 # #
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7
7
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10 pdebug = false
10 pdebug = false
11 ################################################################################
11 ################################################################################
12 ## Uncomment and replace with the address which should receive ##
12 ## Uncomment and replace with the address which should receive ##
13 ## any error reports after application crash ##
13 ## any error reports after application crash ##
14 ## Additionally those settings will be used by RhodeCode mailing system ##
14 ## Additionally those settings will be used by RhodeCode mailing system ##
15 ################################################################################
15 ################################################################################
16 #email_to = admin@localhost
16 #email_to = admin@localhost
17 #error_email_from = paste_error@localhost
17 #error_email_from = paste_error@localhost
18 #app_email_from = rhodecode-noreply@localhost
18 #app_email_from = rhodecode-noreply@localhost
19 #error_message =
19 #error_message =
20 #email_prefix = [RhodeCode]
20 #email_prefix = [RhodeCode]
21
21
22 #smtp_server = mail.server.com
22 #smtp_server = mail.server.com
23 #smtp_username =
23 #smtp_username =
24 #smtp_password =
24 #smtp_password =
25 #smtp_port =
25 #smtp_port =
26 #smtp_use_tls = false
26 #smtp_use_tls = false
27 #smtp_use_ssl = true
27 #smtp_use_ssl = true
28 # Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
28 # Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
29 #smtp_auth =
29 #smtp_auth =
30
30
31 [server:main]
31 [server:main]
32 ## PASTE
32 ## PASTE
33 ##nr of threads to spawn
33 ##nr of threads to spawn
34 #threadpool_workers = 5
34 #threadpool_workers = 5
35
35
36 ##max request before thread respawn
36 ##max request before thread respawn
37 #threadpool_max_requests = 10
37 #threadpool_max_requests = 10
38
38
39 ##option to use threads of process
39 ##option to use threads of process
40 #use_threadpool = true
40 #use_threadpool = true
41
41
42 #use = egg:Paste#http
42 #use = egg:Paste#http
43
43
44 #WAITRESS
44 #WAITRESS
45 threads = 5
45 threads = 5
46 #100GB
46 #100GB
47 max_request_body_size = 107374182400
47 max_request_body_size = 107374182400
48 use = egg:waitress#main
48 use = egg:waitress#main
49
49
50 host = 0.0.0.0
50 host = 0.0.0.0
51 port = 5000
51 port = 5000
52
52
53 [filter:proxy-prefix]
53 [filter:proxy-prefix]
54 # prefix middleware for rc
54 # prefix middleware for rc
55 use = egg:PasteDeploy#prefix
55 use = egg:PasteDeploy#prefix
56 prefix = /<your-prefix>
56 prefix = /<your-prefix>
57
57
58 [app:main]
58 [app:main]
59 use = egg:rhodecode
59 use = egg:rhodecode
60 #filter-with = proxy-prefix
60 #filter-with = proxy-prefix
61 full_stack = true
61 full_stack = true
62 static_files = true
62 static_files = true
63 # Optional Languages
63 # Optional Languages
64 # en, fr, ja, pt_BR, zh_CN, zh_TW, pl
64 # en, fr, ja, pt_BR, zh_CN, zh_TW, pl
65 lang = en
65 lang = en
66 cache_dir = %(here)s/data
66 cache_dir = %(here)s/data
67 index_dir = %(here)s/data/index
67 index_dir = %(here)s/data/index
68 # set this path to use archive download cache
68 # set this path to use archive download cache
69 #archive_cache_dir = /tmp/rhodecode_tarballcache
69 #archive_cache_dir = /tmp/rhodecode_tarballcache
70 app_instance_uuid = rc-develop
70 app_instance_uuid = rc-develop
71 cut_off_limit = 256000
71 cut_off_limit = 256000
72 vcs_full_cache = True
72 vcs_full_cache = True
73 # force https in RhodeCode, fixes https redirects, assumes it's always https
73 # force https in RhodeCode, fixes https redirects, assumes it's always https
74 force_https = false
74 force_https = false
75 # use Strict-Transport-Security headers
75 # use Strict-Transport-Security headers
76 use_htsts = false
76 use_htsts = false
77 commit_parse_limit = 25
77 commit_parse_limit = 25
78 # number of items displayed in lightweight dashboard before paginating
78 # number of items displayed in lightweight dashboard before paginating
79 dashboard_items = 100
79 dashboard_items = 100
80 use_gravatar = true
80 use_gravatar = true
81
81
82 # path to git executable
82 # path to git executable
83 git_path = git
83 git_path = git
84
84
85 ## RSS feed options
85 ## RSS feed options
86
86
87 rss_cut_off_limit = 256000
87 rss_cut_off_limit = 256000
88 rss_items_per_page = 10
88 rss_items_per_page = 10
89 rss_include_diff = false
89 rss_include_diff = false
90
90
91
91
92 ## alternative_gravatar_url allows you to use your own avatar server application
92 ## alternative_gravatar_url allows you to use your own avatar server application
93 ## the following parts of the URL will be replaced
93 ## the following parts of the URL will be replaced
94 ## {email} user email
94 ## {email} user email
95 ## {md5email} md5 hash of the user email (like at gravatar.com)
95 ## {md5email} md5 hash of the user email (like at gravatar.com)
96 ## {size} size of the image that is expected from the server application
96 ## {size} size of the image that is expected from the server application
97 ## {scheme} http/https from RhodeCode server
97 ## {scheme} http/https from RhodeCode server
98 ## {netloc} network location from RhodeCode server
98 ## {netloc} network location from RhodeCode server
99 #alternative_gravatar_url = http://myavatarserver.com/getbyemail/{email}/{size}
99 #alternative_gravatar_url = http://myavatarserver.com/getbyemail/{email}/{size}
100 #alternative_gravatar_url = http://myavatarserver.com/getbymd5/{md5email}?s={size}
100 #alternative_gravatar_url = http://myavatarserver.com/getbymd5/{md5email}?s={size}
101
101
102 container_auth_enabled = false
102 container_auth_enabled = false
103 proxypass_auth_enabled = false
103 proxypass_auth_enabled = false
104 ## default encoding used to convert from and to unicode
104 ## default encoding used to convert from and to unicode
105 ## can be also a comma seperated list of encoding in case of mixed encodings
105 ## can be also a comma seperated list of encoding in case of mixed encodings
106 default_encoding = utf8
106 default_encoding = utf8
107
107
108 ## overwrite schema of clone url
108 ## overwrite schema of clone url
109 ## available vars:
109 ## available vars:
110 ## scheme - http/https
110 ## scheme - http/https
111 ## user - current user
111 ## user - current user
112 ## pass - password
112 ## pass - password
113 ## netloc - network location
113 ## netloc - network location
114 ## path - usually repo_name
114 ## path - usually repo_name
115
115
116 #clone_uri = {scheme}://{user}{pass}{netloc}{path}
116 #clone_uri = {scheme}://{user}{pass}{netloc}{path}
117
117
118 ## issue tracking mapping for commits messages
118 ## issue tracking mapping for commits messages
119 ## comment out issue_pat, issue_server, issue_prefix to enable
119 ## comment out issue_pat, issue_server, issue_prefix to enable
120
120
121 ## pattern to get the issues from commit messages
121 ## pattern to get the issues from commit messages
122 ## default one used here is #<numbers> with a regex passive group for `#`
122 ## default one used here is #<numbers> with a regex passive group for `#`
123 ## {id} will be all groups matched from this pattern
123 ## {id} will be all groups matched from this pattern
124
124
125 issue_pat = (?:\s*#)(\d+)
125 issue_pat = (?:\s*#)(\d+)
126
126
127 ## server url to the issue, each {id} will be replaced with match
127 ## server url to the issue, each {id} will be replaced with match
128 ## fetched from the regex and {repo} is replaced with full repository name
128 ## fetched from the regex and {repo} is replaced with full repository name
129 ## including groups {repo_name} is replaced with just name of repo
129 ## including groups {repo_name} is replaced with just name of repo
130
130
131 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
131 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
132
132
133 ## prefix to add to link to indicate it's an url
133 ## prefix to add to link to indicate it's an url
134 ## #314 will be replaced by <issue_prefix><id>
134 ## #314 will be replaced by <issue_prefix><id>
135
135
136 issue_prefix = #
136 issue_prefix = #
137
137
138 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
138 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
139 ## multiple patterns, to other issues server, wiki or others
139 ## multiple patterns, to other issues server, wiki or others
140 ## below an example how to create a wiki pattern
140 ## below an example how to create a wiki pattern
141 # #wiki-some-id -> https://mywiki.com/some-id
141 # #wiki-some-id -> https://mywiki.com/some-id
142
142
143 #issue_pat_wiki = (?:wiki-)(.+)
143 #issue_pat_wiki = (?:wiki-)(.+)
144 #issue_server_link_wiki = https://mywiki.com/{id}
144 #issue_server_link_wiki = https://mywiki.com/{id}
145 #issue_prefix_wiki = WIKI-
145 #issue_prefix_wiki = WIKI-
146
146
147
147
148 ## instance-id prefix
148 ## instance-id prefix
149 ## a prefix key for this instance used for cache invalidation when running
149 ## a prefix key for this instance used for cache invalidation when running
150 ## multiple instances of rhodecode, make sure it's globally unique for
150 ## multiple instances of rhodecode, make sure it's globally unique for
151 ## all running rhodecode instances. Leave empty if you don't use it
151 ## all running rhodecode instances. Leave empty if you don't use it
152 instance_id =
152 instance_id =
153
153
154 ## alternative return HTTP header for failed authentication. Default HTTP
154 ## alternative return HTTP header for failed authentication. Default HTTP
155 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
155 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
156 ## handling that. Set this variable to 403 to return HTTPForbidden
156 ## handling that. Set this variable to 403 to return HTTPForbidden
157 auth_ret_code =
157 auth_ret_code =
158
158
159 ## locking return code. When repository is locked return this HTTP code. 2XX
160 ## codes don't break the transactions while 4XX codes do
161 lock_ret_code = 423
162
163
159 ####################################
164 ####################################
160 ### CELERY CONFIG ####
165 ### CELERY CONFIG ####
161 ####################################
166 ####################################
162 use_celery = false
167 use_celery = false
163 broker.host = localhost
168 broker.host = localhost
164 broker.vhost = rabbitmqhost
169 broker.vhost = rabbitmqhost
165 broker.port = 5672
170 broker.port = 5672
166 broker.user = rabbitmq
171 broker.user = rabbitmq
167 broker.password = qweqwe
172 broker.password = qweqwe
168
173
169 celery.imports = rhodecode.lib.celerylib.tasks
174 celery.imports = rhodecode.lib.celerylib.tasks
170
175
171 celery.result.backend = amqp
176 celery.result.backend = amqp
172 celery.result.dburi = amqp://
177 celery.result.dburi = amqp://
173 celery.result.serialier = json
178 celery.result.serialier = json
174
179
175 #celery.send.task.error.emails = true
180 #celery.send.task.error.emails = true
176 #celery.amqp.task.result.expires = 18000
181 #celery.amqp.task.result.expires = 18000
177
182
178 celeryd.concurrency = 2
183 celeryd.concurrency = 2
179 #celeryd.log.file = celeryd.log
184 #celeryd.log.file = celeryd.log
180 celeryd.log.level = debug
185 celeryd.log.level = debug
181 celeryd.max.tasks.per.child = 1
186 celeryd.max.tasks.per.child = 1
182
187
183 #tasks will never be sent to the queue, but executed locally instead.
188 #tasks will never be sent to the queue, but executed locally instead.
184 celery.always.eager = false
189 celery.always.eager = false
185
190
186 ####################################
191 ####################################
187 ### BEAKER CACHE ####
192 ### BEAKER CACHE ####
188 ####################################
193 ####################################
189 beaker.cache.data_dir=%(here)s/data/cache/data
194 beaker.cache.data_dir=%(here)s/data/cache/data
190 beaker.cache.lock_dir=%(here)s/data/cache/lock
195 beaker.cache.lock_dir=%(here)s/data/cache/lock
191
196
192 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
197 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
193
198
194 beaker.cache.super_short_term.type=memory
199 beaker.cache.super_short_term.type=memory
195 beaker.cache.super_short_term.expire=10
200 beaker.cache.super_short_term.expire=10
196 beaker.cache.super_short_term.key_length = 256
201 beaker.cache.super_short_term.key_length = 256
197
202
198 beaker.cache.short_term.type=memory
203 beaker.cache.short_term.type=memory
199 beaker.cache.short_term.expire=60
204 beaker.cache.short_term.expire=60
200 beaker.cache.short_term.key_length = 256
205 beaker.cache.short_term.key_length = 256
201
206
202 beaker.cache.long_term.type=memory
207 beaker.cache.long_term.type=memory
203 beaker.cache.long_term.expire=36000
208 beaker.cache.long_term.expire=36000
204 beaker.cache.long_term.key_length = 256
209 beaker.cache.long_term.key_length = 256
205
210
206 beaker.cache.sql_cache_short.type=memory
211 beaker.cache.sql_cache_short.type=memory
207 beaker.cache.sql_cache_short.expire=10
212 beaker.cache.sql_cache_short.expire=10
208 beaker.cache.sql_cache_short.key_length = 256
213 beaker.cache.sql_cache_short.key_length = 256
209
214
210 beaker.cache.sql_cache_med.type=memory
215 beaker.cache.sql_cache_med.type=memory
211 beaker.cache.sql_cache_med.expire=360
216 beaker.cache.sql_cache_med.expire=360
212 beaker.cache.sql_cache_med.key_length = 256
217 beaker.cache.sql_cache_med.key_length = 256
213
218
214 beaker.cache.sql_cache_long.type=file
219 beaker.cache.sql_cache_long.type=file
215 beaker.cache.sql_cache_long.expire=3600
220 beaker.cache.sql_cache_long.expire=3600
216 beaker.cache.sql_cache_long.key_length = 256
221 beaker.cache.sql_cache_long.key_length = 256
217
222
218 ####################################
223 ####################################
219 ### BEAKER SESSION ####
224 ### BEAKER SESSION ####
220 ####################################
225 ####################################
221 ## Type of storage used for the session, current types are
226 ## Type of storage used for the session, current types are
222 ## dbm, file, memcached, database, and memory.
227 ## dbm, file, memcached, database, and memory.
223 ## The storage uses the Container API
228 ## The storage uses the Container API
224 ## that is also used by the cache system.
229 ## that is also used by the cache system.
225
230
226 ## db session ##
231 ## db session ##
227 #beaker.session.type = ext:database
232 #beaker.session.type = ext:database
228 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/rhodecode
233 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/rhodecode
229 #beaker.session.table_name = db_session
234 #beaker.session.table_name = db_session
230
235
231 ## encrypted cookie client side session, good for many instances ##
236 ## encrypted cookie client side session, good for many instances ##
232 #beaker.session.type = cookie
237 #beaker.session.type = cookie
233
238
234 ## file based cookies (default) ##
239 ## file based cookies (default) ##
235 #beaker.session.type = file
240 #beaker.session.type = file
236
241
237
242
238 beaker.session.key = rhodecode
243 beaker.session.key = rhodecode
239 ## secure cookie requires AES python libraries ##
244 ## secure cookie requires AES python libraries ##
240 #beaker.session.encrypt_key = g654dcno0-9873jhgfreyu
245 #beaker.session.encrypt_key = g654dcno0-9873jhgfreyu
241 #beaker.session.validate_key = 9712sds2212c--zxc123
246 #beaker.session.validate_key = 9712sds2212c--zxc123
242 ## sets session as invalid if it haven't been accessed for given amount of time
247 ## sets session as invalid if it haven't been accessed for given amount of time
243 beaker.session.timeout = 2592000
248 beaker.session.timeout = 2592000
244 beaker.session.httponly = true
249 beaker.session.httponly = true
245 #beaker.session.cookie_path = /<your-prefix>
250 #beaker.session.cookie_path = /<your-prefix>
246
251
247 ## uncomment for https secure cookie ##
252 ## uncomment for https secure cookie ##
248 beaker.session.secure = false
253 beaker.session.secure = false
249
254
250 ## auto save the session to not to use .save() ##
255 ## auto save the session to not to use .save() ##
251 beaker.session.auto = False
256 beaker.session.auto = False
252
257
253 ## default cookie expiration time in seconds `true` expire at browser close ##
258 ## default cookie expiration time in seconds `true` expire at browser close ##
254 #beaker.session.cookie_expires = 3600
259 #beaker.session.cookie_expires = 3600
255
260
256
261
257 ############################
262 ############################
258 ## ERROR HANDLING SYSTEMS ##
263 ## ERROR HANDLING SYSTEMS ##
259 ############################
264 ############################
260
265
261 ####################
266 ####################
262 ### [errormator] ###
267 ### [errormator] ###
263 ####################
268 ####################
264
269
265 # Errormator is tailored to work with RhodeCode, see
270 # Errormator is tailored to work with RhodeCode, see
266 # http://errormator.com for details how to obtain an account
271 # http://errormator.com for details how to obtain an account
267 # you must install python package `errormator_client` to make it work
272 # you must install python package `errormator_client` to make it work
268
273
269 # errormator enabled
274 # errormator enabled
270 errormator = true
275 errormator = true
271
276
272 errormator.server_url = https://api.errormator.com
277 errormator.server_url = https://api.errormator.com
273 errormator.api_key = YOUR_API_KEY
278 errormator.api_key = YOUR_API_KEY
274
279
275 # TWEAK AMOUNT OF INFO SENT HERE
280 # TWEAK AMOUNT OF INFO SENT HERE
276
281
277 # enables 404 error logging (default False)
282 # enables 404 error logging (default False)
278 errormator.report_404 = false
283 errormator.report_404 = false
279
284
280 # time in seconds after request is considered being slow (default 1)
285 # time in seconds after request is considered being slow (default 1)
281 errormator.slow_request_time = 1
286 errormator.slow_request_time = 1
282
287
283 # record slow requests in application
288 # record slow requests in application
284 # (needs to be enabled for slow datastore recording and time tracking)
289 # (needs to be enabled for slow datastore recording and time tracking)
285 errormator.slow_requests = true
290 errormator.slow_requests = true
286
291
287 # enable hooking to application loggers
292 # enable hooking to application loggers
288 # errormator.logging = true
293 # errormator.logging = true
289
294
290 # minimum log level for log capture
295 # minimum log level for log capture
291 # errormator.logging.level = WARNING
296 # errormator.logging.level = WARNING
292
297
293 # send logs only from erroneous/slow requests
298 # send logs only from erroneous/slow requests
294 # (saves API quota for intensive logging)
299 # (saves API quota for intensive logging)
295 errormator.logging_on_error = false
300 errormator.logging_on_error = false
296
301
297 # list of additonal keywords that should be grabbed from environ object
302 # list of additonal keywords that should be grabbed from environ object
298 # can be string with comma separated list of words in lowercase
303 # can be string with comma separated list of words in lowercase
299 # (by default client will always send following info:
304 # (by default client will always send following info:
300 # 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
305 # 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
301 # start with HTTP* this list be extended with additional keywords here
306 # start with HTTP* this list be extended with additional keywords here
302 errormator.environ_keys_whitelist =
307 errormator.environ_keys_whitelist =
303
308
304
309
305 # list of keywords that should be blanked from request object
310 # list of keywords that should be blanked from request object
306 # can be string with comma separated list of words in lowercase
311 # can be string with comma separated list of words in lowercase
307 # (by default client will always blank keys that contain following words
312 # (by default client will always blank keys that contain following words
308 # 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
313 # 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
309 # this list be extended with additional keywords set here
314 # this list be extended with additional keywords set here
310 errormator.request_keys_blacklist =
315 errormator.request_keys_blacklist =
311
316
312
317
313 # list of namespaces that should be ignores when gathering log entries
318 # list of namespaces that should be ignores when gathering log entries
314 # can be string with comma separated list of namespaces
319 # can be string with comma separated list of namespaces
315 # (by default the client ignores own entries: errormator_client.client)
320 # (by default the client ignores own entries: errormator_client.client)
316 errormator.log_namespace_blacklist =
321 errormator.log_namespace_blacklist =
317
322
318
323
319 ################
324 ################
320 ### [sentry] ###
325 ### [sentry] ###
321 ################
326 ################
322
327
323 # sentry is a alternative open source error aggregator
328 # sentry is a alternative open source error aggregator
324 # you must install python packages `sentry` and `raven` to enable
329 # you must install python packages `sentry` and `raven` to enable
325
330
326 sentry.dsn = YOUR_DNS
331 sentry.dsn = YOUR_DNS
327 sentry.servers =
332 sentry.servers =
328 sentry.name =
333 sentry.name =
329 sentry.key =
334 sentry.key =
330 sentry.public_key =
335 sentry.public_key =
331 sentry.secret_key =
336 sentry.secret_key =
332 sentry.project =
337 sentry.project =
333 sentry.site =
338 sentry.site =
334 sentry.include_paths =
339 sentry.include_paths =
335 sentry.exclude_paths =
340 sentry.exclude_paths =
336
341
337
342
338 ################################################################################
343 ################################################################################
339 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
344 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
340 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
345 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
341 ## execute malicious code after an exception is raised. ##
346 ## execute malicious code after an exception is raised. ##
342 ################################################################################
347 ################################################################################
343 #set debug = false
348 #set debug = false
344
349
345 ##################################
350 ##################################
346 ### LOGVIEW CONFIG ###
351 ### LOGVIEW CONFIG ###
347 ##################################
352 ##################################
348 logview.sqlalchemy = #faa
353 logview.sqlalchemy = #faa
349 logview.pylons.templating = #bfb
354 logview.pylons.templating = #bfb
350 logview.pylons.util = #eee
355 logview.pylons.util = #eee
351
356
352 #########################################################
357 #########################################################
353 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
358 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
354 #########################################################
359 #########################################################
355 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
360 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
356 sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode
361 sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode
357 sqlalchemy.db1.echo = false
362 sqlalchemy.db1.echo = false
358 sqlalchemy.db1.pool_recycle = 3600
363 sqlalchemy.db1.pool_recycle = 3600
359 sqlalchemy.db1.convert_unicode = true
364 sqlalchemy.db1.convert_unicode = true
360
365
361 ################################
366 ################################
362 ### LOGGING CONFIGURATION ####
367 ### LOGGING CONFIGURATION ####
363 ################################
368 ################################
364 [loggers]
369 [loggers]
365 keys = root, routes, rhodecode, sqlalchemy, beaker, templates, whoosh_indexer
370 keys = root, routes, rhodecode, sqlalchemy, beaker, templates, whoosh_indexer
366
371
367 [handlers]
372 [handlers]
368 keys = console, console_sql
373 keys = console, console_sql
369
374
370 [formatters]
375 [formatters]
371 keys = generic, color_formatter, color_formatter_sql
376 keys = generic, color_formatter, color_formatter_sql
372
377
373 #############
378 #############
374 ## LOGGERS ##
379 ## LOGGERS ##
375 #############
380 #############
376 [logger_root]
381 [logger_root]
377 level = NOTSET
382 level = NOTSET
378 handlers = console
383 handlers = console
379
384
380 [logger_routes]
385 [logger_routes]
381 level = DEBUG
386 level = DEBUG
382 handlers =
387 handlers =
383 qualname = routes.middleware
388 qualname = routes.middleware
384 # "level = DEBUG" logs the route matched and routing variables.
389 # "level = DEBUG" logs the route matched and routing variables.
385 propagate = 1
390 propagate = 1
386
391
387 [logger_beaker]
392 [logger_beaker]
388 level = DEBUG
393 level = DEBUG
389 handlers =
394 handlers =
390 qualname = beaker.container
395 qualname = beaker.container
391 propagate = 1
396 propagate = 1
392
397
393 [logger_templates]
398 [logger_templates]
394 level = INFO
399 level = INFO
395 handlers =
400 handlers =
396 qualname = pylons.templating
401 qualname = pylons.templating
397 propagate = 1
402 propagate = 1
398
403
399 [logger_rhodecode]
404 [logger_rhodecode]
400 level = DEBUG
405 level = DEBUG
401 handlers =
406 handlers =
402 qualname = rhodecode
407 qualname = rhodecode
403 propagate = 1
408 propagate = 1
404
409
405 [logger_sqlalchemy]
410 [logger_sqlalchemy]
406 level = INFO
411 level = INFO
407 handlers = console_sql
412 handlers = console_sql
408 qualname = sqlalchemy.engine
413 qualname = sqlalchemy.engine
409 propagate = 0
414 propagate = 0
410
415
411 [logger_whoosh_indexer]
416 [logger_whoosh_indexer]
412 level = DEBUG
417 level = DEBUG
413 handlers =
418 handlers =
414 qualname = whoosh_indexer
419 qualname = whoosh_indexer
415 propagate = 1
420 propagate = 1
416
421
417 ##############
422 ##############
418 ## HANDLERS ##
423 ## HANDLERS ##
419 ##############
424 ##############
420
425
421 [handler_console]
426 [handler_console]
422 class = StreamHandler
427 class = StreamHandler
423 args = (sys.stderr,)
428 args = (sys.stderr,)
424 level = DEBUG
429 level = DEBUG
425 formatter = color_formatter
430 formatter = color_formatter
426
431
427 [handler_console_sql]
432 [handler_console_sql]
428 class = StreamHandler
433 class = StreamHandler
429 args = (sys.stderr,)
434 args = (sys.stderr,)
430 level = DEBUG
435 level = DEBUG
431 formatter = color_formatter_sql
436 formatter = color_formatter_sql
432
437
433 ################
438 ################
434 ## FORMATTERS ##
439 ## FORMATTERS ##
435 ################
440 ################
436
441
437 [formatter_generic]
442 [formatter_generic]
438 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
443 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
439 datefmt = %Y-%m-%d %H:%M:%S
444 datefmt = %Y-%m-%d %H:%M:%S
440
445
441 [formatter_color_formatter]
446 [formatter_color_formatter]
442 class=rhodecode.lib.colored_formatter.ColorFormatter
447 class=rhodecode.lib.colored_formatter.ColorFormatter
443 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
448 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
444 datefmt = %Y-%m-%d %H:%M:%S
449 datefmt = %Y-%m-%d %H:%M:%S
445
450
446 [formatter_color_formatter_sql]
451 [formatter_color_formatter_sql]
447 class=rhodecode.lib.colored_formatter.ColorFormatterSql
452 class=rhodecode.lib.colored_formatter.ColorFormatterSql
448 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
453 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
449 datefmt = %Y-%m-%d %H:%M:%S
454 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,449 +1,454 b''
1 ################################################################################
1 ################################################################################
2 ################################################################################
2 ################################################################################
3 # RhodeCode - Pylons environment configuration #
3 # RhodeCode - Pylons environment configuration #
4 # #
4 # #
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7
7
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10 pdebug = false
10 pdebug = false
11 ################################################################################
11 ################################################################################
12 ## Uncomment and replace with the address which should receive ##
12 ## Uncomment and replace with the address which should receive ##
13 ## any error reports after application crash ##
13 ## any error reports after application crash ##
14 ## Additionally those settings will be used by RhodeCode mailing system ##
14 ## Additionally those settings will be used by RhodeCode mailing system ##
15 ################################################################################
15 ################################################################################
16 #email_to = admin@localhost
16 #email_to = admin@localhost
17 #error_email_from = paste_error@localhost
17 #error_email_from = paste_error@localhost
18 #app_email_from = rhodecode-noreply@localhost
18 #app_email_from = rhodecode-noreply@localhost
19 #error_message =
19 #error_message =
20 #email_prefix = [RhodeCode]
20 #email_prefix = [RhodeCode]
21
21
22 #smtp_server = mail.server.com
22 #smtp_server = mail.server.com
23 #smtp_username =
23 #smtp_username =
24 #smtp_password =
24 #smtp_password =
25 #smtp_port =
25 #smtp_port =
26 #smtp_use_tls = false
26 #smtp_use_tls = false
27 #smtp_use_ssl = true
27 #smtp_use_ssl = true
28 # Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
28 # Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
29 #smtp_auth =
29 #smtp_auth =
30
30
31 [server:main]
31 [server:main]
32 ## PASTE
32 ## PASTE
33 ##nr of threads to spawn
33 ##nr of threads to spawn
34 #threadpool_workers = 5
34 #threadpool_workers = 5
35
35
36 ##max request before thread respawn
36 ##max request before thread respawn
37 #threadpool_max_requests = 10
37 #threadpool_max_requests = 10
38
38
39 ##option to use threads of process
39 ##option to use threads of process
40 #use_threadpool = true
40 #use_threadpool = true
41
41
42 #use = egg:Paste#http
42 #use = egg:Paste#http
43
43
44 #WAITRESS
44 #WAITRESS
45 threads = 5
45 threads = 5
46 #100GB
46 #100GB
47 max_request_body_size = 107374182400
47 max_request_body_size = 107374182400
48 use = egg:waitress#main
48 use = egg:waitress#main
49
49
50 host = 127.0.0.1
50 host = 127.0.0.1
51 port = 8001
51 port = 8001
52
52
53 [filter:proxy-prefix]
53 [filter:proxy-prefix]
54 # prefix middleware for rc
54 # prefix middleware for rc
55 use = egg:PasteDeploy#prefix
55 use = egg:PasteDeploy#prefix
56 prefix = /<your-prefix>
56 prefix = /<your-prefix>
57
57
58 [app:main]
58 [app:main]
59 use = egg:rhodecode
59 use = egg:rhodecode
60 #filter-with = proxy-prefix
60 #filter-with = proxy-prefix
61 full_stack = true
61 full_stack = true
62 static_files = true
62 static_files = true
63 # Optional Languages
63 # Optional Languages
64 # en, fr, ja, pt_BR, zh_CN, zh_TW, pl
64 # en, fr, ja, pt_BR, zh_CN, zh_TW, pl
65 lang = en
65 lang = en
66 cache_dir = %(here)s/data
66 cache_dir = %(here)s/data
67 index_dir = %(here)s/data/index
67 index_dir = %(here)s/data/index
68 # set this path to use archive download cache
68 # set this path to use archive download cache
69 #archive_cache_dir = /tmp/rhodecode_tarballcache
69 #archive_cache_dir = /tmp/rhodecode_tarballcache
70 app_instance_uuid = rc-production
70 app_instance_uuid = rc-production
71 cut_off_limit = 256000
71 cut_off_limit = 256000
72 vcs_full_cache = True
72 vcs_full_cache = True
73 # force https in RhodeCode, fixes https redirects, assumes it's always https
73 # force https in RhodeCode, fixes https redirects, assumes it's always https
74 force_https = false
74 force_https = false
75 # use Strict-Transport-Security headers
75 # use Strict-Transport-Security headers
76 use_htsts = false
76 use_htsts = false
77 commit_parse_limit = 50
77 commit_parse_limit = 50
78 # number of items displayed in lightweight dashboard before paginating
78 # number of items displayed in lightweight dashboard before paginating
79 dashboard_items = 100
79 dashboard_items = 100
80 use_gravatar = true
80 use_gravatar = true
81
81
82 # path to git executable
82 # path to git executable
83 git_path = git
83 git_path = git
84
84
85 ## RSS feed options
85 ## RSS feed options
86
86
87 rss_cut_off_limit = 256000
87 rss_cut_off_limit = 256000
88 rss_items_per_page = 10
88 rss_items_per_page = 10
89 rss_include_diff = false
89 rss_include_diff = false
90
90
91
91
92 ## alternative_gravatar_url allows you to use your own avatar server application
92 ## alternative_gravatar_url allows you to use your own avatar server application
93 ## the following parts of the URL will be replaced
93 ## the following parts of the URL will be replaced
94 ## {email} user email
94 ## {email} user email
95 ## {md5email} md5 hash of the user email (like at gravatar.com)
95 ## {md5email} md5 hash of the user email (like at gravatar.com)
96 ## {size} size of the image that is expected from the server application
96 ## {size} size of the image that is expected from the server application
97 ## {scheme} http/https from RhodeCode server
97 ## {scheme} http/https from RhodeCode server
98 ## {netloc} network location from RhodeCode server
98 ## {netloc} network location from RhodeCode server
99 #alternative_gravatar_url = http://myavatarserver.com/getbyemail/{email}/{size}
99 #alternative_gravatar_url = http://myavatarserver.com/getbyemail/{email}/{size}
100 #alternative_gravatar_url = http://myavatarserver.com/getbymd5/{md5email}?s={size}
100 #alternative_gravatar_url = http://myavatarserver.com/getbymd5/{md5email}?s={size}
101
101
102 container_auth_enabled = false
102 container_auth_enabled = false
103 proxypass_auth_enabled = false
103 proxypass_auth_enabled = false
104 ## default encoding used to convert from and to unicode
104 ## default encoding used to convert from and to unicode
105 ## can be also a comma seperated list of encoding in case of mixed encodings
105 ## can be also a comma seperated list of encoding in case of mixed encodings
106 default_encoding = utf8
106 default_encoding = utf8
107
107
108 ## overwrite schema of clone url
108 ## overwrite schema of clone url
109 ## available vars:
109 ## available vars:
110 ## scheme - http/https
110 ## scheme - http/https
111 ## user - current user
111 ## user - current user
112 ## pass - password
112 ## pass - password
113 ## netloc - network location
113 ## netloc - network location
114 ## path - usually repo_name
114 ## path - usually repo_name
115
115
116 #clone_uri = {scheme}://{user}{pass}{netloc}{path}
116 #clone_uri = {scheme}://{user}{pass}{netloc}{path}
117
117
118 ## issue tracking mapping for commits messages
118 ## issue tracking mapping for commits messages
119 ## comment out issue_pat, issue_server, issue_prefix to enable
119 ## comment out issue_pat, issue_server, issue_prefix to enable
120
120
121 ## pattern to get the issues from commit messages
121 ## pattern to get the issues from commit messages
122 ## default one used here is #<numbers> with a regex passive group for `#`
122 ## default one used here is #<numbers> with a regex passive group for `#`
123 ## {id} will be all groups matched from this pattern
123 ## {id} will be all groups matched from this pattern
124
124
125 issue_pat = (?:\s*#)(\d+)
125 issue_pat = (?:\s*#)(\d+)
126
126
127 ## server url to the issue, each {id} will be replaced with match
127 ## server url to the issue, each {id} will be replaced with match
128 ## fetched from the regex and {repo} is replaced with full repository name
128 ## fetched from the regex and {repo} is replaced with full repository name
129 ## including groups {repo_name} is replaced with just name of repo
129 ## including groups {repo_name} is replaced with just name of repo
130
130
131 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
131 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
132
132
133 ## prefix to add to link to indicate it's an url
133 ## prefix to add to link to indicate it's an url
134 ## #314 will be replaced by <issue_prefix><id>
134 ## #314 will be replaced by <issue_prefix><id>
135
135
136 issue_prefix = #
136 issue_prefix = #
137
137
138 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
138 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
139 ## multiple patterns, to other issues server, wiki or others
139 ## multiple patterns, to other issues server, wiki or others
140 ## below an example how to create a wiki pattern
140 ## below an example how to create a wiki pattern
141 # #wiki-some-id -> https://mywiki.com/some-id
141 # #wiki-some-id -> https://mywiki.com/some-id
142
142
143 #issue_pat_wiki = (?:wiki-)(.+)
143 #issue_pat_wiki = (?:wiki-)(.+)
144 #issue_server_link_wiki = https://mywiki.com/{id}
144 #issue_server_link_wiki = https://mywiki.com/{id}
145 #issue_prefix_wiki = WIKI-
145 #issue_prefix_wiki = WIKI-
146
146
147
147
148 ## instance-id prefix
148 ## instance-id prefix
149 ## a prefix key for this instance used for cache invalidation when running
149 ## a prefix key for this instance used for cache invalidation when running
150 ## multiple instances of rhodecode, make sure it's globally unique for
150 ## multiple instances of rhodecode, make sure it's globally unique for
151 ## all running rhodecode instances. Leave empty if you don't use it
151 ## all running rhodecode instances. Leave empty if you don't use it
152 instance_id =
152 instance_id =
153
153
154 ## alternative return HTTP header for failed authentication. Default HTTP
154 ## alternative return HTTP header for failed authentication. Default HTTP
155 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
155 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
156 ## handling that. Set this variable to 403 to return HTTPForbidden
156 ## handling that. Set this variable to 403 to return HTTPForbidden
157 auth_ret_code =
157 auth_ret_code =
158
158
159 ## locking return code. When repository is locked return this HTTP code. 2XX
160 ## codes don't break the transactions while 4XX codes do
161 lock_ret_code = 423
162
163
159 ####################################
164 ####################################
160 ### CELERY CONFIG ####
165 ### CELERY CONFIG ####
161 ####################################
166 ####################################
162 use_celery = false
167 use_celery = false
163 broker.host = localhost
168 broker.host = localhost
164 broker.vhost = rabbitmqhost
169 broker.vhost = rabbitmqhost
165 broker.port = 5672
170 broker.port = 5672
166 broker.user = rabbitmq
171 broker.user = rabbitmq
167 broker.password = qweqwe
172 broker.password = qweqwe
168
173
169 celery.imports = rhodecode.lib.celerylib.tasks
174 celery.imports = rhodecode.lib.celerylib.tasks
170
175
171 celery.result.backend = amqp
176 celery.result.backend = amqp
172 celery.result.dburi = amqp://
177 celery.result.dburi = amqp://
173 celery.result.serialier = json
178 celery.result.serialier = json
174
179
175 #celery.send.task.error.emails = true
180 #celery.send.task.error.emails = true
176 #celery.amqp.task.result.expires = 18000
181 #celery.amqp.task.result.expires = 18000
177
182
178 celeryd.concurrency = 2
183 celeryd.concurrency = 2
179 #celeryd.log.file = celeryd.log
184 #celeryd.log.file = celeryd.log
180 celeryd.log.level = debug
185 celeryd.log.level = debug
181 celeryd.max.tasks.per.child = 1
186 celeryd.max.tasks.per.child = 1
182
187
183 #tasks will never be sent to the queue, but executed locally instead.
188 #tasks will never be sent to the queue, but executed locally instead.
184 celery.always.eager = false
189 celery.always.eager = false
185
190
186 ####################################
191 ####################################
187 ### BEAKER CACHE ####
192 ### BEAKER CACHE ####
188 ####################################
193 ####################################
189 beaker.cache.data_dir=%(here)s/data/cache/data
194 beaker.cache.data_dir=%(here)s/data/cache/data
190 beaker.cache.lock_dir=%(here)s/data/cache/lock
195 beaker.cache.lock_dir=%(here)s/data/cache/lock
191
196
192 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
197 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
193
198
194 beaker.cache.super_short_term.type=memory
199 beaker.cache.super_short_term.type=memory
195 beaker.cache.super_short_term.expire=10
200 beaker.cache.super_short_term.expire=10
196 beaker.cache.super_short_term.key_length = 256
201 beaker.cache.super_short_term.key_length = 256
197
202
198 beaker.cache.short_term.type=memory
203 beaker.cache.short_term.type=memory
199 beaker.cache.short_term.expire=60
204 beaker.cache.short_term.expire=60
200 beaker.cache.short_term.key_length = 256
205 beaker.cache.short_term.key_length = 256
201
206
202 beaker.cache.long_term.type=memory
207 beaker.cache.long_term.type=memory
203 beaker.cache.long_term.expire=36000
208 beaker.cache.long_term.expire=36000
204 beaker.cache.long_term.key_length = 256
209 beaker.cache.long_term.key_length = 256
205
210
206 beaker.cache.sql_cache_short.type=memory
211 beaker.cache.sql_cache_short.type=memory
207 beaker.cache.sql_cache_short.expire=10
212 beaker.cache.sql_cache_short.expire=10
208 beaker.cache.sql_cache_short.key_length = 256
213 beaker.cache.sql_cache_short.key_length = 256
209
214
210 beaker.cache.sql_cache_med.type=memory
215 beaker.cache.sql_cache_med.type=memory
211 beaker.cache.sql_cache_med.expire=360
216 beaker.cache.sql_cache_med.expire=360
212 beaker.cache.sql_cache_med.key_length = 256
217 beaker.cache.sql_cache_med.key_length = 256
213
218
214 beaker.cache.sql_cache_long.type=file
219 beaker.cache.sql_cache_long.type=file
215 beaker.cache.sql_cache_long.expire=3600
220 beaker.cache.sql_cache_long.expire=3600
216 beaker.cache.sql_cache_long.key_length = 256
221 beaker.cache.sql_cache_long.key_length = 256
217
222
218 ####################################
223 ####################################
219 ### BEAKER SESSION ####
224 ### BEAKER SESSION ####
220 ####################################
225 ####################################
221 ## Type of storage used for the session, current types are
226 ## Type of storage used for the session, current types are
222 ## dbm, file, memcached, database, and memory.
227 ## dbm, file, memcached, database, and memory.
223 ## The storage uses the Container API
228 ## The storage uses the Container API
224 ## that is also used by the cache system.
229 ## that is also used by the cache system.
225
230
226 ## db session ##
231 ## db session ##
227 #beaker.session.type = ext:database
232 #beaker.session.type = ext:database
228 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/rhodecode
233 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/rhodecode
229 #beaker.session.table_name = db_session
234 #beaker.session.table_name = db_session
230
235
231 ## encrypted cookie client side session, good for many instances ##
236 ## encrypted cookie client side session, good for many instances ##
232 #beaker.session.type = cookie
237 #beaker.session.type = cookie
233
238
234 ## file based cookies (default) ##
239 ## file based cookies (default) ##
235 #beaker.session.type = file
240 #beaker.session.type = file
236
241
237
242
238 beaker.session.key = rhodecode
243 beaker.session.key = rhodecode
239 ## secure cookie requires AES python libraries ##
244 ## secure cookie requires AES python libraries ##
240 #beaker.session.encrypt_key = g654dcno0-9873jhgfreyu
245 #beaker.session.encrypt_key = g654dcno0-9873jhgfreyu
241 #beaker.session.validate_key = 9712sds2212c--zxc123
246 #beaker.session.validate_key = 9712sds2212c--zxc123
242 ## sets session as invalid if it haven't been accessed for given amount of time
247 ## sets session as invalid if it haven't been accessed for given amount of time
243 beaker.session.timeout = 2592000
248 beaker.session.timeout = 2592000
244 beaker.session.httponly = true
249 beaker.session.httponly = true
245 #beaker.session.cookie_path = /<your-prefix>
250 #beaker.session.cookie_path = /<your-prefix>
246
251
247 ## uncomment for https secure cookie ##
252 ## uncomment for https secure cookie ##
248 beaker.session.secure = false
253 beaker.session.secure = false
249
254
250 ## auto save the session to not to use .save() ##
255 ## auto save the session to not to use .save() ##
251 beaker.session.auto = False
256 beaker.session.auto = False
252
257
253 ## default cookie expiration time in seconds `true` expire at browser close ##
258 ## default cookie expiration time in seconds `true` expire at browser close ##
254 #beaker.session.cookie_expires = 3600
259 #beaker.session.cookie_expires = 3600
255
260
256
261
257 ############################
262 ############################
258 ## ERROR HANDLING SYSTEMS ##
263 ## ERROR HANDLING SYSTEMS ##
259 ############################
264 ############################
260
265
261 ####################
266 ####################
262 ### [errormator] ###
267 ### [errormator] ###
263 ####################
268 ####################
264
269
265 # Errormator is tailored to work with RhodeCode, see
270 # Errormator is tailored to work with RhodeCode, see
266 # http://errormator.com for details how to obtain an account
271 # http://errormator.com for details how to obtain an account
267 # you must install python package `errormator_client` to make it work
272 # you must install python package `errormator_client` to make it work
268
273
269 # errormator enabled
274 # errormator enabled
270 errormator = true
275 errormator = true
271
276
272 errormator.server_url = https://api.errormator.com
277 errormator.server_url = https://api.errormator.com
273 errormator.api_key = YOUR_API_KEY
278 errormator.api_key = YOUR_API_KEY
274
279
275 # TWEAK AMOUNT OF INFO SENT HERE
280 # TWEAK AMOUNT OF INFO SENT HERE
276
281
277 # enables 404 error logging (default False)
282 # enables 404 error logging (default False)
278 errormator.report_404 = false
283 errormator.report_404 = false
279
284
280 # time in seconds after request is considered being slow (default 1)
285 # time in seconds after request is considered being slow (default 1)
281 errormator.slow_request_time = 1
286 errormator.slow_request_time = 1
282
287
283 # record slow requests in application
288 # record slow requests in application
284 # (needs to be enabled for slow datastore recording and time tracking)
289 # (needs to be enabled for slow datastore recording and time tracking)
285 errormator.slow_requests = true
290 errormator.slow_requests = true
286
291
287 # enable hooking to application loggers
292 # enable hooking to application loggers
288 # errormator.logging = true
293 # errormator.logging = true
289
294
290 # minimum log level for log capture
295 # minimum log level for log capture
291 # errormator.logging.level = WARNING
296 # errormator.logging.level = WARNING
292
297
293 # send logs only from erroneous/slow requests
298 # send logs only from erroneous/slow requests
294 # (saves API quota for intensive logging)
299 # (saves API quota for intensive logging)
295 errormator.logging_on_error = false
300 errormator.logging_on_error = false
296
301
297 # list of additonal keywords that should be grabbed from environ object
302 # list of additonal keywords that should be grabbed from environ object
298 # can be string with comma separated list of words in lowercase
303 # can be string with comma separated list of words in lowercase
299 # (by default client will always send following info:
304 # (by default client will always send following info:
300 # 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
305 # 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
301 # start with HTTP* this list be extended with additional keywords here
306 # start with HTTP* this list be extended with additional keywords here
302 errormator.environ_keys_whitelist =
307 errormator.environ_keys_whitelist =
303
308
304
309
305 # list of keywords that should be blanked from request object
310 # list of keywords that should be blanked from request object
306 # can be string with comma separated list of words in lowercase
311 # can be string with comma separated list of words in lowercase
307 # (by default client will always blank keys that contain following words
312 # (by default client will always blank keys that contain following words
308 # 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
313 # 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
309 # this list be extended with additional keywords set here
314 # this list be extended with additional keywords set here
310 errormator.request_keys_blacklist =
315 errormator.request_keys_blacklist =
311
316
312
317
313 # list of namespaces that should be ignores when gathering log entries
318 # list of namespaces that should be ignores when gathering log entries
314 # can be string with comma separated list of namespaces
319 # can be string with comma separated list of namespaces
315 # (by default the client ignores own entries: errormator_client.client)
320 # (by default the client ignores own entries: errormator_client.client)
316 errormator.log_namespace_blacklist =
321 errormator.log_namespace_blacklist =
317
322
318
323
319 ################
324 ################
320 ### [sentry] ###
325 ### [sentry] ###
321 ################
326 ################
322
327
323 # sentry is a alternative open source error aggregator
328 # sentry is a alternative open source error aggregator
324 # you must install python packages `sentry` and `raven` to enable
329 # you must install python packages `sentry` and `raven` to enable
325
330
326 sentry.dsn = YOUR_DNS
331 sentry.dsn = YOUR_DNS
327 sentry.servers =
332 sentry.servers =
328 sentry.name =
333 sentry.name =
329 sentry.key =
334 sentry.key =
330 sentry.public_key =
335 sentry.public_key =
331 sentry.secret_key =
336 sentry.secret_key =
332 sentry.project =
337 sentry.project =
333 sentry.site =
338 sentry.site =
334 sentry.include_paths =
339 sentry.include_paths =
335 sentry.exclude_paths =
340 sentry.exclude_paths =
336
341
337
342
338 ################################################################################
343 ################################################################################
339 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
344 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
340 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
345 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
341 ## execute malicious code after an exception is raised. ##
346 ## execute malicious code after an exception is raised. ##
342 ################################################################################
347 ################################################################################
343 set debug = false
348 set debug = false
344
349
345 ##################################
350 ##################################
346 ### LOGVIEW CONFIG ###
351 ### LOGVIEW CONFIG ###
347 ##################################
352 ##################################
348 logview.sqlalchemy = #faa
353 logview.sqlalchemy = #faa
349 logview.pylons.templating = #bfb
354 logview.pylons.templating = #bfb
350 logview.pylons.util = #eee
355 logview.pylons.util = #eee
351
356
352 #########################################################
357 #########################################################
353 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
358 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
354 #########################################################
359 #########################################################
355 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
360 #sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
356 sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode
361 sqlalchemy.db1.url = postgresql://postgres:qwe@localhost/rhodecode
357 sqlalchemy.db1.echo = false
362 sqlalchemy.db1.echo = false
358 sqlalchemy.db1.pool_recycle = 3600
363 sqlalchemy.db1.pool_recycle = 3600
359 sqlalchemy.db1.convert_unicode = true
364 sqlalchemy.db1.convert_unicode = true
360
365
361 ################################
366 ################################
362 ### LOGGING CONFIGURATION ####
367 ### LOGGING CONFIGURATION ####
363 ################################
368 ################################
364 [loggers]
369 [loggers]
365 keys = root, routes, rhodecode, sqlalchemy, beaker, templates, whoosh_indexer
370 keys = root, routes, rhodecode, sqlalchemy, beaker, templates, whoosh_indexer
366
371
367 [handlers]
372 [handlers]
368 keys = console, console_sql
373 keys = console, console_sql
369
374
370 [formatters]
375 [formatters]
371 keys = generic, color_formatter, color_formatter_sql
376 keys = generic, color_formatter, color_formatter_sql
372
377
373 #############
378 #############
374 ## LOGGERS ##
379 ## LOGGERS ##
375 #############
380 #############
376 [logger_root]
381 [logger_root]
377 level = NOTSET
382 level = NOTSET
378 handlers = console
383 handlers = console
379
384
380 [logger_routes]
385 [logger_routes]
381 level = DEBUG
386 level = DEBUG
382 handlers =
387 handlers =
383 qualname = routes.middleware
388 qualname = routes.middleware
384 # "level = DEBUG" logs the route matched and routing variables.
389 # "level = DEBUG" logs the route matched and routing variables.
385 propagate = 1
390 propagate = 1
386
391
387 [logger_beaker]
392 [logger_beaker]
388 level = DEBUG
393 level = DEBUG
389 handlers =
394 handlers =
390 qualname = beaker.container
395 qualname = beaker.container
391 propagate = 1
396 propagate = 1
392
397
393 [logger_templates]
398 [logger_templates]
394 level = INFO
399 level = INFO
395 handlers =
400 handlers =
396 qualname = pylons.templating
401 qualname = pylons.templating
397 propagate = 1
402 propagate = 1
398
403
399 [logger_rhodecode]
404 [logger_rhodecode]
400 level = DEBUG
405 level = DEBUG
401 handlers =
406 handlers =
402 qualname = rhodecode
407 qualname = rhodecode
403 propagate = 1
408 propagate = 1
404
409
405 [logger_sqlalchemy]
410 [logger_sqlalchemy]
406 level = INFO
411 level = INFO
407 handlers = console_sql
412 handlers = console_sql
408 qualname = sqlalchemy.engine
413 qualname = sqlalchemy.engine
409 propagate = 0
414 propagate = 0
410
415
411 [logger_whoosh_indexer]
416 [logger_whoosh_indexer]
412 level = DEBUG
417 level = DEBUG
413 handlers =
418 handlers =
414 qualname = whoosh_indexer
419 qualname = whoosh_indexer
415 propagate = 1
420 propagate = 1
416
421
417 ##############
422 ##############
418 ## HANDLERS ##
423 ## HANDLERS ##
419 ##############
424 ##############
420
425
421 [handler_console]
426 [handler_console]
422 class = StreamHandler
427 class = StreamHandler
423 args = (sys.stderr,)
428 args = (sys.stderr,)
424 level = INFO
429 level = INFO
425 formatter = generic
430 formatter = generic
426
431
427 [handler_console_sql]
432 [handler_console_sql]
428 class = StreamHandler
433 class = StreamHandler
429 args = (sys.stderr,)
434 args = (sys.stderr,)
430 level = WARN
435 level = WARN
431 formatter = generic
436 formatter = generic
432
437
433 ################
438 ################
434 ## FORMATTERS ##
439 ## FORMATTERS ##
435 ################
440 ################
436
441
437 [formatter_generic]
442 [formatter_generic]
438 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
443 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
439 datefmt = %Y-%m-%d %H:%M:%S
444 datefmt = %Y-%m-%d %H:%M:%S
440
445
441 [formatter_color_formatter]
446 [formatter_color_formatter]
442 class=rhodecode.lib.colored_formatter.ColorFormatter
447 class=rhodecode.lib.colored_formatter.ColorFormatter
443 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
448 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
444 datefmt = %Y-%m-%d %H:%M:%S
449 datefmt = %Y-%m-%d %H:%M:%S
445
450
446 [formatter_color_formatter_sql]
451 [formatter_color_formatter_sql]
447 class=rhodecode.lib.colored_formatter.ColorFormatterSql
452 class=rhodecode.lib.colored_formatter.ColorFormatterSql
448 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
453 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
449 datefmt = %Y-%m-%d %H:%M:%S
454 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,459 +1,464 b''
1 ################################################################################
1 ################################################################################
2 ################################################################################
2 ################################################################################
3 # RhodeCode - Pylons environment configuration #
3 # RhodeCode - Pylons environment configuration #
4 # #
4 # #
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7
7
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10 pdebug = false
10 pdebug = false
11 ################################################################################
11 ################################################################################
12 ## Uncomment and replace with the address which should receive ##
12 ## Uncomment and replace with the address which should receive ##
13 ## any error reports after application crash ##
13 ## any error reports after application crash ##
14 ## Additionally those settings will be used by RhodeCode mailing system ##
14 ## Additionally those settings will be used by RhodeCode mailing system ##
15 ################################################################################
15 ################################################################################
16 #email_to = admin@localhost
16 #email_to = admin@localhost
17 #error_email_from = paste_error@localhost
17 #error_email_from = paste_error@localhost
18 #app_email_from = rhodecode-noreply@localhost
18 #app_email_from = rhodecode-noreply@localhost
19 #error_message =
19 #error_message =
20 #email_prefix = [RhodeCode]
20 #email_prefix = [RhodeCode]
21
21
22 #smtp_server = mail.server.com
22 #smtp_server = mail.server.com
23 #smtp_username =
23 #smtp_username =
24 #smtp_password =
24 #smtp_password =
25 #smtp_port =
25 #smtp_port =
26 #smtp_use_tls = false
26 #smtp_use_tls = false
27 #smtp_use_ssl = true
27 #smtp_use_ssl = true
28 # Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
28 # Specify available auth parameters here (e.g. LOGIN PLAIN CRAM-MD5, etc.)
29 #smtp_auth =
29 #smtp_auth =
30
30
31 [server:main]
31 [server:main]
32 ## PASTE
32 ## PASTE
33 ##nr of threads to spawn
33 ##nr of threads to spawn
34 #threadpool_workers = 5
34 #threadpool_workers = 5
35
35
36 ##max request before thread respawn
36 ##max request before thread respawn
37 #threadpool_max_requests = 10
37 #threadpool_max_requests = 10
38
38
39 ##option to use threads of process
39 ##option to use threads of process
40 #use_threadpool = true
40 #use_threadpool = true
41
41
42 #use = egg:Paste#http
42 #use = egg:Paste#http
43
43
44 #WAITRESS
44 #WAITRESS
45 threads = 5
45 threads = 5
46 #100GB
46 #100GB
47 max_request_body_size = 107374182400
47 max_request_body_size = 107374182400
48 use = egg:waitress#main
48 use = egg:waitress#main
49
49
50 host = 127.0.0.1
50 host = 127.0.0.1
51 port = 5000
51 port = 5000
52
52
53 [filter:proxy-prefix]
53 [filter:proxy-prefix]
54 # prefix middleware for rc
54 # prefix middleware for rc
55 use = egg:PasteDeploy#prefix
55 use = egg:PasteDeploy#prefix
56 prefix = /<your-prefix>
56 prefix = /<your-prefix>
57
57
58 [app:main]
58 [app:main]
59 use = egg:rhodecode
59 use = egg:rhodecode
60 #filter-with = proxy-prefix
60 #filter-with = proxy-prefix
61 full_stack = true
61 full_stack = true
62 static_files = true
62 static_files = true
63 # Optional Languages
63 # Optional Languages
64 # en, fr, ja, pt_BR, zh_CN, zh_TW, pl
64 # en, fr, ja, pt_BR, zh_CN, zh_TW, pl
65 lang = en
65 lang = en
66 cache_dir = %(here)s/data
66 cache_dir = %(here)s/data
67 index_dir = %(here)s/data/index
67 index_dir = %(here)s/data/index
68 # set this path to use archive download cache
68 # set this path to use archive download cache
69 #archive_cache_dir = /tmp/rhodecode_tarballcache
69 #archive_cache_dir = /tmp/rhodecode_tarballcache
70 app_instance_uuid = ${app_instance_uuid}
70 app_instance_uuid = ${app_instance_uuid}
71 cut_off_limit = 256000
71 cut_off_limit = 256000
72 vcs_full_cache = True
72 vcs_full_cache = True
73 # force https in RhodeCode, fixes https redirects, assumes it's always https
73 # force https in RhodeCode, fixes https redirects, assumes it's always https
74 force_https = false
74 force_https = false
75 # use Strict-Transport-Security headers
75 # use Strict-Transport-Security headers
76 use_htsts = false
76 use_htsts = false
77 commit_parse_limit = 50
77 commit_parse_limit = 50
78 # number of items displayed in lightweight dashboard before paginating
78 # number of items displayed in lightweight dashboard before paginating
79 dashboard_items = 100
79 dashboard_items = 100
80 use_gravatar = true
80 use_gravatar = true
81
81
82 # path to git executable
82 # path to git executable
83 git_path = git
83 git_path = git
84
84
85 ## RSS feed options
85 ## RSS feed options
86
86
87 rss_cut_off_limit = 256000
87 rss_cut_off_limit = 256000
88 rss_items_per_page = 10
88 rss_items_per_page = 10
89 rss_include_diff = false
89 rss_include_diff = false
90
90
91
91
92 ## alternative_gravatar_url allows you to use your own avatar server application
92 ## alternative_gravatar_url allows you to use your own avatar server application
93 ## the following parts of the URL will be replaced
93 ## the following parts of the URL will be replaced
94 ## {email} user email
94 ## {email} user email
95 ## {md5email} md5 hash of the user email (like at gravatar.com)
95 ## {md5email} md5 hash of the user email (like at gravatar.com)
96 ## {size} size of the image that is expected from the server application
96 ## {size} size of the image that is expected from the server application
97 ## {scheme} http/https from RhodeCode server
97 ## {scheme} http/https from RhodeCode server
98 ## {netloc} network location from RhodeCode server
98 ## {netloc} network location from RhodeCode server
99 #alternative_gravatar_url = http://myavatarserver.com/getbyemail/{email}/{size}
99 #alternative_gravatar_url = http://myavatarserver.com/getbyemail/{email}/{size}
100 #alternative_gravatar_url = http://myavatarserver.com/getbymd5/{md5email}?s={size}
100 #alternative_gravatar_url = http://myavatarserver.com/getbymd5/{md5email}?s={size}
101
101
102 container_auth_enabled = false
102 container_auth_enabled = false
103 proxypass_auth_enabled = false
103 proxypass_auth_enabled = false
104 ## default encoding used to convert from and to unicode
104 ## default encoding used to convert from and to unicode
105 ## can be also a comma seperated list of encoding in case of mixed encodings
105 ## can be also a comma seperated list of encoding in case of mixed encodings
106 default_encoding = utf8
106 default_encoding = utf8
107
107
108 ## overwrite schema of clone url
108 ## overwrite schema of clone url
109 ## available vars:
109 ## available vars:
110 ## scheme - http/https
110 ## scheme - http/https
111 ## user - current user
111 ## user - current user
112 ## pass - password
112 ## pass - password
113 ## netloc - network location
113 ## netloc - network location
114 ## path - usually repo_name
114 ## path - usually repo_name
115
115
116 #clone_uri = {scheme}://{user}{pass}{netloc}{path}
116 #clone_uri = {scheme}://{user}{pass}{netloc}{path}
117
117
118 ## issue tracking mapping for commits messages
118 ## issue tracking mapping for commits messages
119 ## comment out issue_pat, issue_server, issue_prefix to enable
119 ## comment out issue_pat, issue_server, issue_prefix to enable
120
120
121 ## pattern to get the issues from commit messages
121 ## pattern to get the issues from commit messages
122 ## default one used here is #<numbers> with a regex passive group for `#`
122 ## default one used here is #<numbers> with a regex passive group for `#`
123 ## {id} will be all groups matched from this pattern
123 ## {id} will be all groups matched from this pattern
124
124
125 issue_pat = (?:\s*#)(\d+)
125 issue_pat = (?:\s*#)(\d+)
126
126
127 ## server url to the issue, each {id} will be replaced with match
127 ## server url to the issue, each {id} will be replaced with match
128 ## fetched from the regex and {repo} is replaced with full repository name
128 ## fetched from the regex and {repo} is replaced with full repository name
129 ## including groups {repo_name} is replaced with just name of repo
129 ## including groups {repo_name} is replaced with just name of repo
130
130
131 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
131 issue_server_link = https://myissueserver.com/{repo}/issue/{id}
132
132
133 ## prefix to add to link to indicate it's an url
133 ## prefix to add to link to indicate it's an url
134 ## #314 will be replaced by <issue_prefix><id>
134 ## #314 will be replaced by <issue_prefix><id>
135
135
136 issue_prefix = #
136 issue_prefix = #
137
137
138 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
138 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
139 ## multiple patterns, to other issues server, wiki or others
139 ## multiple patterns, to other issues server, wiki or others
140 ## below an example how to create a wiki pattern
140 ## below an example how to create a wiki pattern
141 # #wiki-some-id -> https://mywiki.com/some-id
141 # #wiki-some-id -> https://mywiki.com/some-id
142
142
143 #issue_pat_wiki = (?:wiki-)(.+)
143 #issue_pat_wiki = (?:wiki-)(.+)
144 #issue_server_link_wiki = https://mywiki.com/{id}
144 #issue_server_link_wiki = https://mywiki.com/{id}
145 #issue_prefix_wiki = WIKI-
145 #issue_prefix_wiki = WIKI-
146
146
147
147
148 ## instance-id prefix
148 ## instance-id prefix
149 ## a prefix key for this instance used for cache invalidation when running
149 ## a prefix key for this instance used for cache invalidation when running
150 ## multiple instances of rhodecode, make sure it's globally unique for
150 ## multiple instances of rhodecode, make sure it's globally unique for
151 ## all running rhodecode instances. Leave empty if you don't use it
151 ## all running rhodecode instances. Leave empty if you don't use it
152 instance_id =
152 instance_id =
153
153
154 ## alternative return HTTP header for failed authentication. Default HTTP
154 ## alternative return HTTP header for failed authentication. Default HTTP
155 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
155 ## response is 401 HTTPUnauthorized. Currently HG clients have troubles with
156 ## handling that. Set this variable to 403 to return HTTPForbidden
156 ## handling that. Set this variable to 403 to return HTTPForbidden
157 auth_ret_code =
157 auth_ret_code =
158
158
159 ## locking return code. When repository is locked return this HTTP code. 2XX
160 ## codes don't break the transactions while 4XX codes do
161 lock_ret_code = 423
162
163
159 ####################################
164 ####################################
160 ### CELERY CONFIG ####
165 ### CELERY CONFIG ####
161 ####################################
166 ####################################
162 use_celery = false
167 use_celery = false
163 broker.host = localhost
168 broker.host = localhost
164 broker.vhost = rabbitmqhost
169 broker.vhost = rabbitmqhost
165 broker.port = 5672
170 broker.port = 5672
166 broker.user = rabbitmq
171 broker.user = rabbitmq
167 broker.password = qweqwe
172 broker.password = qweqwe
168
173
169 celery.imports = rhodecode.lib.celerylib.tasks
174 celery.imports = rhodecode.lib.celerylib.tasks
170
175
171 celery.result.backend = amqp
176 celery.result.backend = amqp
172 celery.result.dburi = amqp://
177 celery.result.dburi = amqp://
173 celery.result.serialier = json
178 celery.result.serialier = json
174
179
175 #celery.send.task.error.emails = true
180 #celery.send.task.error.emails = true
176 #celery.amqp.task.result.expires = 18000
181 #celery.amqp.task.result.expires = 18000
177
182
178 celeryd.concurrency = 2
183 celeryd.concurrency = 2
179 #celeryd.log.file = celeryd.log
184 #celeryd.log.file = celeryd.log
180 celeryd.log.level = debug
185 celeryd.log.level = debug
181 celeryd.max.tasks.per.child = 1
186 celeryd.max.tasks.per.child = 1
182
187
183 #tasks will never be sent to the queue, but executed locally instead.
188 #tasks will never be sent to the queue, but executed locally instead.
184 celery.always.eager = false
189 celery.always.eager = false
185
190
186 ####################################
191 ####################################
187 ### BEAKER CACHE ####
192 ### BEAKER CACHE ####
188 ####################################
193 ####################################
189 beaker.cache.data_dir=%(here)s/data/cache/data
194 beaker.cache.data_dir=%(here)s/data/cache/data
190 beaker.cache.lock_dir=%(here)s/data/cache/lock
195 beaker.cache.lock_dir=%(here)s/data/cache/lock
191
196
192 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
197 beaker.cache.regions=super_short_term,short_term,long_term,sql_cache_short,sql_cache_med,sql_cache_long
193
198
194 beaker.cache.super_short_term.type=memory
199 beaker.cache.super_short_term.type=memory
195 beaker.cache.super_short_term.expire=10
200 beaker.cache.super_short_term.expire=10
196 beaker.cache.super_short_term.key_length = 256
201 beaker.cache.super_short_term.key_length = 256
197
202
198 beaker.cache.short_term.type=memory
203 beaker.cache.short_term.type=memory
199 beaker.cache.short_term.expire=60
204 beaker.cache.short_term.expire=60
200 beaker.cache.short_term.key_length = 256
205 beaker.cache.short_term.key_length = 256
201
206
202 beaker.cache.long_term.type=memory
207 beaker.cache.long_term.type=memory
203 beaker.cache.long_term.expire=36000
208 beaker.cache.long_term.expire=36000
204 beaker.cache.long_term.key_length = 256
209 beaker.cache.long_term.key_length = 256
205
210
206 beaker.cache.sql_cache_short.type=memory
211 beaker.cache.sql_cache_short.type=memory
207 beaker.cache.sql_cache_short.expire=10
212 beaker.cache.sql_cache_short.expire=10
208 beaker.cache.sql_cache_short.key_length = 256
213 beaker.cache.sql_cache_short.key_length = 256
209
214
210 beaker.cache.sql_cache_med.type=memory
215 beaker.cache.sql_cache_med.type=memory
211 beaker.cache.sql_cache_med.expire=360
216 beaker.cache.sql_cache_med.expire=360
212 beaker.cache.sql_cache_med.key_length = 256
217 beaker.cache.sql_cache_med.key_length = 256
213
218
214 beaker.cache.sql_cache_long.type=file
219 beaker.cache.sql_cache_long.type=file
215 beaker.cache.sql_cache_long.expire=3600
220 beaker.cache.sql_cache_long.expire=3600
216 beaker.cache.sql_cache_long.key_length = 256
221 beaker.cache.sql_cache_long.key_length = 256
217
222
218 ####################################
223 ####################################
219 ### BEAKER SESSION ####
224 ### BEAKER SESSION ####
220 ####################################
225 ####################################
221 ## Type of storage used for the session, current types are
226 ## Type of storage used for the session, current types are
222 ## dbm, file, memcached, database, and memory.
227 ## dbm, file, memcached, database, and memory.
223 ## The storage uses the Container API
228 ## The storage uses the Container API
224 ## that is also used by the cache system.
229 ## that is also used by the cache system.
225
230
226 ## db session ##
231 ## db session ##
227 #beaker.session.type = ext:database
232 #beaker.session.type = ext:database
228 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/rhodecode
233 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/rhodecode
229 #beaker.session.table_name = db_session
234 #beaker.session.table_name = db_session
230
235
231 ## encrypted cookie client side session, good for many instances ##
236 ## encrypted cookie client side session, good for many instances ##
232 #beaker.session.type = cookie
237 #beaker.session.type = cookie
233
238
234 ## file based cookies (default) ##
239 ## file based cookies (default) ##
235 #beaker.session.type = file
240 #beaker.session.type = file
236
241
237
242
238 beaker.session.key = rhodecode
243 beaker.session.key = rhodecode
239 ## secure cookie requires AES python libraries ##
244 ## secure cookie requires AES python libraries ##
240 #beaker.session.encrypt_key = g654dcno0-9873jhgfreyu
245 #beaker.session.encrypt_key = g654dcno0-9873jhgfreyu
241 #beaker.session.validate_key = 9712sds2212c--zxc123
246 #beaker.session.validate_key = 9712sds2212c--zxc123
242 ## sets session as invalid if it haven't been accessed for given amount of time
247 ## sets session as invalid if it haven't been accessed for given amount of time
243 beaker.session.timeout = 2592000
248 beaker.session.timeout = 2592000
244 beaker.session.httponly = true
249 beaker.session.httponly = true
245 #beaker.session.cookie_path = /<your-prefix>
250 #beaker.session.cookie_path = /<your-prefix>
246
251
247 ## uncomment for https secure cookie ##
252 ## uncomment for https secure cookie ##
248 beaker.session.secure = false
253 beaker.session.secure = false
249
254
250 ## auto save the session to not to use .save() ##
255 ## auto save the session to not to use .save() ##
251 beaker.session.auto = False
256 beaker.session.auto = False
252
257
253 ## default cookie expiration time in seconds `true` expire at browser close ##
258 ## default cookie expiration time in seconds `true` expire at browser close ##
254 #beaker.session.cookie_expires = 3600
259 #beaker.session.cookie_expires = 3600
255
260
256
261
257 ############################
262 ############################
258 ## ERROR HANDLING SYSTEMS ##
263 ## ERROR HANDLING SYSTEMS ##
259 ############################
264 ############################
260
265
261 ####################
266 ####################
262 ### [errormator] ###
267 ### [errormator] ###
263 ####################
268 ####################
264
269
265 # Errormator is tailored to work with RhodeCode, see
270 # Errormator is tailored to work with RhodeCode, see
266 # http://errormator.com for details how to obtain an account
271 # http://errormator.com for details how to obtain an account
267 # you must install python package `errormator_client` to make it work
272 # you must install python package `errormator_client` to make it work
268
273
269 # errormator enabled
274 # errormator enabled
270 errormator = true
275 errormator = true
271
276
272 errormator.server_url = https://api.errormator.com
277 errormator.server_url = https://api.errormator.com
273 errormator.api_key = YOUR_API_KEY
278 errormator.api_key = YOUR_API_KEY
274
279
275 # TWEAK AMOUNT OF INFO SENT HERE
280 # TWEAK AMOUNT OF INFO SENT HERE
276
281
277 # enables 404 error logging (default False)
282 # enables 404 error logging (default False)
278 errormator.report_404 = false
283 errormator.report_404 = false
279
284
280 # time in seconds after request is considered being slow (default 1)
285 # time in seconds after request is considered being slow (default 1)
281 errormator.slow_request_time = 1
286 errormator.slow_request_time = 1
282
287
283 # record slow requests in application
288 # record slow requests in application
284 # (needs to be enabled for slow datastore recording and time tracking)
289 # (needs to be enabled for slow datastore recording and time tracking)
285 errormator.slow_requests = true
290 errormator.slow_requests = true
286
291
287 # enable hooking to application loggers
292 # enable hooking to application loggers
288 # errormator.logging = true
293 # errormator.logging = true
289
294
290 # minimum log level for log capture
295 # minimum log level for log capture
291 # errormator.logging.level = WARNING
296 # errormator.logging.level = WARNING
292
297
293 # send logs only from erroneous/slow requests
298 # send logs only from erroneous/slow requests
294 # (saves API quota for intensive logging)
299 # (saves API quota for intensive logging)
295 errormator.logging_on_error = false
300 errormator.logging_on_error = false
296
301
297 # list of additonal keywords that should be grabbed from environ object
302 # list of additonal keywords that should be grabbed from environ object
298 # can be string with comma separated list of words in lowercase
303 # can be string with comma separated list of words in lowercase
299 # (by default client will always send following info:
304 # (by default client will always send following info:
300 # 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
305 # 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
301 # start with HTTP* this list be extended with additional keywords here
306 # start with HTTP* this list be extended with additional keywords here
302 errormator.environ_keys_whitelist =
307 errormator.environ_keys_whitelist =
303
308
304
309
305 # list of keywords that should be blanked from request object
310 # list of keywords that should be blanked from request object
306 # can be string with comma separated list of words in lowercase
311 # can be string with comma separated list of words in lowercase
307 # (by default client will always blank keys that contain following words
312 # (by default client will always blank keys that contain following words
308 # 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
313 # 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
309 # this list be extended with additional keywords set here
314 # this list be extended with additional keywords set here
310 errormator.request_keys_blacklist =
315 errormator.request_keys_blacklist =
311
316
312
317
313 # list of namespaces that should be ignores when gathering log entries
318 # list of namespaces that should be ignores when gathering log entries
314 # can be string with comma separated list of namespaces
319 # can be string with comma separated list of namespaces
315 # (by default the client ignores own entries: errormator_client.client)
320 # (by default the client ignores own entries: errormator_client.client)
316 errormator.log_namespace_blacklist =
321 errormator.log_namespace_blacklist =
317
322
318
323
319 ################
324 ################
320 ### [sentry] ###
325 ### [sentry] ###
321 ################
326 ################
322
327
323 # sentry is a alternative open source error aggregator
328 # sentry is a alternative open source error aggregator
324 # you must install python packages `sentry` and `raven` to enable
329 # you must install python packages `sentry` and `raven` to enable
325
330
326 sentry.dsn = YOUR_DNS
331 sentry.dsn = YOUR_DNS
327 sentry.servers =
332 sentry.servers =
328 sentry.name =
333 sentry.name =
329 sentry.key =
334 sentry.key =
330 sentry.public_key =
335 sentry.public_key =
331 sentry.secret_key =
336 sentry.secret_key =
332 sentry.project =
337 sentry.project =
333 sentry.site =
338 sentry.site =
334 sentry.include_paths =
339 sentry.include_paths =
335 sentry.exclude_paths =
340 sentry.exclude_paths =
336
341
337
342
338 ################################################################################
343 ################################################################################
339 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
344 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
340 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
345 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
341 ## execute malicious code after an exception is raised. ##
346 ## execute malicious code after an exception is raised. ##
342 ################################################################################
347 ################################################################################
343 set debug = false
348 set debug = false
344
349
345 ##################################
350 ##################################
346 ### LOGVIEW CONFIG ###
351 ### LOGVIEW CONFIG ###
347 ##################################
352 ##################################
348 logview.sqlalchemy = #faa
353 logview.sqlalchemy = #faa
349 logview.pylons.templating = #bfb
354 logview.pylons.templating = #bfb
350 logview.pylons.util = #eee
355 logview.pylons.util = #eee
351
356
352 #########################################################
357 #########################################################
353 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
358 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
354 #########################################################
359 #########################################################
355
360
356 # SQLITE [default]
361 # SQLITE [default]
357 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
362 sqlalchemy.db1.url = sqlite:///%(here)s/rhodecode.db
358
363
359 # POSTGRESQL
364 # POSTGRESQL
360 # sqlalchemy.db1.url = postgresql://user:pass@localhost/rhodecode
365 # sqlalchemy.db1.url = postgresql://user:pass@localhost/rhodecode
361
366
362 # MySQL
367 # MySQL
363 # sqlalchemy.db1.url = mysql://user:pass@localhost/rhodecode
368 # sqlalchemy.db1.url = mysql://user:pass@localhost/rhodecode
364
369
365 # see sqlalchemy docs for others
370 # see sqlalchemy docs for others
366
371
367 sqlalchemy.db1.echo = false
372 sqlalchemy.db1.echo = false
368 sqlalchemy.db1.pool_recycle = 3600
373 sqlalchemy.db1.pool_recycle = 3600
369 sqlalchemy.db1.convert_unicode = true
374 sqlalchemy.db1.convert_unicode = true
370
375
371 ################################
376 ################################
372 ### LOGGING CONFIGURATION ####
377 ### LOGGING CONFIGURATION ####
373 ################################
378 ################################
374 [loggers]
379 [loggers]
375 keys = root, routes, rhodecode, sqlalchemy, beaker, templates, whoosh_indexer
380 keys = root, routes, rhodecode, sqlalchemy, beaker, templates, whoosh_indexer
376
381
377 [handlers]
382 [handlers]
378 keys = console, console_sql
383 keys = console, console_sql
379
384
380 [formatters]
385 [formatters]
381 keys = generic, color_formatter, color_formatter_sql
386 keys = generic, color_formatter, color_formatter_sql
382
387
383 #############
388 #############
384 ## LOGGERS ##
389 ## LOGGERS ##
385 #############
390 #############
386 [logger_root]
391 [logger_root]
387 level = NOTSET
392 level = NOTSET
388 handlers = console
393 handlers = console
389
394
390 [logger_routes]
395 [logger_routes]
391 level = DEBUG
396 level = DEBUG
392 handlers =
397 handlers =
393 qualname = routes.middleware
398 qualname = routes.middleware
394 # "level = DEBUG" logs the route matched and routing variables.
399 # "level = DEBUG" logs the route matched and routing variables.
395 propagate = 1
400 propagate = 1
396
401
397 [logger_beaker]
402 [logger_beaker]
398 level = DEBUG
403 level = DEBUG
399 handlers =
404 handlers =
400 qualname = beaker.container
405 qualname = beaker.container
401 propagate = 1
406 propagate = 1
402
407
403 [logger_templates]
408 [logger_templates]
404 level = INFO
409 level = INFO
405 handlers =
410 handlers =
406 qualname = pylons.templating
411 qualname = pylons.templating
407 propagate = 1
412 propagate = 1
408
413
409 [logger_rhodecode]
414 [logger_rhodecode]
410 level = DEBUG
415 level = DEBUG
411 handlers =
416 handlers =
412 qualname = rhodecode
417 qualname = rhodecode
413 propagate = 1
418 propagate = 1
414
419
415 [logger_sqlalchemy]
420 [logger_sqlalchemy]
416 level = INFO
421 level = INFO
417 handlers = console_sql
422 handlers = console_sql
418 qualname = sqlalchemy.engine
423 qualname = sqlalchemy.engine
419 propagate = 0
424 propagate = 0
420
425
421 [logger_whoosh_indexer]
426 [logger_whoosh_indexer]
422 level = DEBUG
427 level = DEBUG
423 handlers =
428 handlers =
424 qualname = whoosh_indexer
429 qualname = whoosh_indexer
425 propagate = 1
430 propagate = 1
426
431
427 ##############
432 ##############
428 ## HANDLERS ##
433 ## HANDLERS ##
429 ##############
434 ##############
430
435
431 [handler_console]
436 [handler_console]
432 class = StreamHandler
437 class = StreamHandler
433 args = (sys.stderr,)
438 args = (sys.stderr,)
434 level = INFO
439 level = INFO
435 formatter = generic
440 formatter = generic
436
441
437 [handler_console_sql]
442 [handler_console_sql]
438 class = StreamHandler
443 class = StreamHandler
439 args = (sys.stderr,)
444 args = (sys.stderr,)
440 level = WARN
445 level = WARN
441 formatter = generic
446 formatter = generic
442
447
443 ################
448 ################
444 ## FORMATTERS ##
449 ## FORMATTERS ##
445 ################
450 ################
446
451
447 [formatter_generic]
452 [formatter_generic]
448 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
453 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
449 datefmt = %Y-%m-%d %H:%M:%S
454 datefmt = %Y-%m-%d %H:%M:%S
450
455
451 [formatter_color_formatter]
456 [formatter_color_formatter]
452 class=rhodecode.lib.colored_formatter.ColorFormatter
457 class=rhodecode.lib.colored_formatter.ColorFormatter
453 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
458 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
454 datefmt = %Y-%m-%d %H:%M:%S
459 datefmt = %Y-%m-%d %H:%M:%S
455
460
456 [formatter_color_formatter_sql]
461 [formatter_color_formatter_sql]
457 class=rhodecode.lib.colored_formatter.ColorFormatterSql
462 class=rhodecode.lib.colored_formatter.ColorFormatterSql
458 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
463 format= %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
459 datefmt = %Y-%m-%d %H:%M:%S
464 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,71 +1,76 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.exceptions
3 rhodecode.lib.exceptions
4 ~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Set of custom exceptions used in RhodeCode
6 Set of custom exceptions used in RhodeCode
7
7
8 :created_on: Nov 17, 2010
8 :created_on: Nov 17, 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 from webob.exc import HTTPClientError
26 from webob.exc import HTTPClientError
27
27
28
28
29 class LdapUsernameError(Exception):
29 class LdapUsernameError(Exception):
30 pass
30 pass
31
31
32
32
33 class LdapPasswordError(Exception):
33 class LdapPasswordError(Exception):
34 pass
34 pass
35
35
36
36
37 class LdapConnectionError(Exception):
37 class LdapConnectionError(Exception):
38 pass
38 pass
39
39
40
40
41 class LdapImportError(Exception):
41 class LdapImportError(Exception):
42 pass
42 pass
43
43
44
44
45 class DefaultUserException(Exception):
45 class DefaultUserException(Exception):
46 pass
46 pass
47
47
48
48
49 class UserOwnsReposException(Exception):
49 class UserOwnsReposException(Exception):
50 pass
50 pass
51
51
52
52
53 class UserGroupsAssignedException(Exception):
53 class UserGroupsAssignedException(Exception):
54 pass
54 pass
55
55
56
56
57 class StatusChangeOnClosedPullRequestError(Exception):
57 class StatusChangeOnClosedPullRequestError(Exception):
58 pass
58 pass
59
59
60
60
61 class HTTPLockedRC(HTTPClientError):
61 class HTTPLockedRC(HTTPClientError):
62 """
62 """
63 Special Exception For locked Repos in RhodeCode
63 Special Exception For locked Repos in RhodeCode, the return code can
64 be overwritten by _code keyword argument passed into constructors
64 """
65 """
65 code = 423
66 code = 423
66 title = explanation = 'Repository Locked'
67 title = explanation = 'Repository Locked'
67
68
68 def __init__(self, reponame, username, *args, **kwargs):
69 def __init__(self, reponame, username, *args, **kwargs):
70 from rhodecode import CONFIG
71 from rhodecode.lib.utils2 import safe_int
72 _code = CONFIG.get('lock_ret_code')
73 self.code = safe_int(_code, self.code)
69 self.title = self.explanation = ('Repository `%s` locked by '
74 self.title = self.explanation = ('Repository `%s` locked by '
70 'user `%s`' % (reponame, username))
75 'user `%s`' % (reponame, username))
71 super(HTTPLockedRC, self).__init__(*args, **kwargs)
76 super(HTTPLockedRC, self).__init__(*args, **kwargs)
@@ -1,437 +1,468 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.hooks
3 rhodecode.lib.hooks
4 ~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~
5
5
6 Hooks runned by rhodecode
6 Hooks runned by rhodecode
7
7
8 :created_on: Aug 6, 2010
8 :created_on: Aug 6, 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 import os
25 import os
26 import sys
26 import sys
27 import time
27 import time
28 import binascii
28 import binascii
29 from inspect import isfunction
29 from inspect import isfunction
30
30
31 from mercurial.scmutil import revrange
31 from mercurial.scmutil import revrange
32 from mercurial.node import nullrev
32 from mercurial.node import nullrev
33
33
34 from rhodecode.lib import helpers as h
34 from rhodecode.lib import helpers as h
35 from rhodecode.lib.utils import action_logger
35 from rhodecode.lib.utils import action_logger
36 from rhodecode.lib.vcs.backends.base import EmptyChangeset
36 from rhodecode.lib.vcs.backends.base import EmptyChangeset
37 from rhodecode.lib.compat import json
37 from rhodecode.lib.compat import json
38 from rhodecode.lib.exceptions import HTTPLockedRC
38 from rhodecode.lib.exceptions import HTTPLockedRC
39 from rhodecode.lib.utils2 import safe_str, datetime_to_time
39 from rhodecode.lib.utils2 import safe_str
40 from rhodecode.model.db import Repository, User
40 from rhodecode.model.db import Repository, User
41
41
42
42
43 def _get_scm_size(alias, root_path):
43 def _get_scm_size(alias, root_path):
44
44
45 if not alias.startswith('.'):
45 if not alias.startswith('.'):
46 alias += '.'
46 alias += '.'
47
47
48 size_scm, size_root = 0, 0
48 size_scm, size_root = 0, 0
49 for path, dirs, files in os.walk(safe_str(root_path)):
49 for path, dirs, files in os.walk(safe_str(root_path)):
50 if path.find(alias) != -1:
50 if path.find(alias) != -1:
51 for f in files:
51 for f in files:
52 try:
52 try:
53 size_scm += os.path.getsize(os.path.join(path, f))
53 size_scm += os.path.getsize(os.path.join(path, f))
54 except OSError:
54 except OSError:
55 pass
55 pass
56 else:
56 else:
57 for f in files:
57 for f in files:
58 try:
58 try:
59 size_root += os.path.getsize(os.path.join(path, f))
59 size_root += os.path.getsize(os.path.join(path, f))
60 except OSError:
60 except OSError:
61 pass
61 pass
62
62
63 size_scm_f = h.format_byte_size(size_scm)
63 size_scm_f = h.format_byte_size(size_scm)
64 size_root_f = h.format_byte_size(size_root)
64 size_root_f = h.format_byte_size(size_root)
65 size_total_f = h.format_byte_size(size_root + size_scm)
65 size_total_f = h.format_byte_size(size_root + size_scm)
66
66
67 return size_scm_f, size_root_f, size_total_f
67 return size_scm_f, size_root_f, size_total_f
68
68
69
69
70 def repo_size(ui, repo, hooktype=None, **kwargs):
70 def repo_size(ui, repo, hooktype=None, **kwargs):
71 """
71 """
72 Presents size of repository after push
72 Presents size of repository after push
73
73
74 :param ui:
74 :param ui:
75 :param repo:
75 :param repo:
76 :param hooktype:
76 :param hooktype:
77 """
77 """
78
78
79 size_hg_f, size_root_f, size_total_f = _get_scm_size('.hg', repo.root)
79 size_hg_f, size_root_f, size_total_f = _get_scm_size('.hg', repo.root)
80
80
81 last_cs = repo[len(repo) - 1]
81 last_cs = repo[len(repo) - 1]
82
82
83 msg = ('Repository size .hg:%s repo:%s total:%s\n'
83 msg = ('Repository size .hg:%s repo:%s total:%s\n'
84 'Last revision is now r%s:%s\n') % (
84 'Last revision is now r%s:%s\n') % (
85 size_hg_f, size_root_f, size_total_f, last_cs.rev(), last_cs.hex()[:12]
85 size_hg_f, size_root_f, size_total_f, last_cs.rev(), last_cs.hex()[:12]
86 )
86 )
87
87
88 sys.stdout.write(msg)
88 sys.stdout.write(msg)
89
89
90
90
91 def pre_push(ui, repo, **kwargs):
91 def pre_push(ui, repo, **kwargs):
92 # pre push function, currently used to ban pushing when
92 # pre push function, currently used to ban pushing when
93 # repository is locked
93 # repository is locked
94 try:
94 try:
95 rc_extras = json.loads(os.environ.get('RC_SCM_DATA', "{}"))
95 rc_extras = json.loads(os.environ.get('RC_SCM_DATA', "{}"))
96 except:
96 except:
97 rc_extras = {}
97 rc_extras = {}
98 extras = dict(repo.ui.configitems('rhodecode_extras'))
98 extras = dict(repo.ui.configitems('rhodecode_extras'))
99
99
100 if 'username' in extras:
100 if 'username' in extras:
101 username = extras['username']
101 username = extras['username']
102 repository = extras['repository']
102 repository = extras['repository']
103 scm = extras['scm']
103 scm = extras['scm']
104 locked_by = extras['locked_by']
104 locked_by = extras['locked_by']
105 elif 'username' in rc_extras:
105 elif 'username' in rc_extras:
106 username = rc_extras['username']
106 username = rc_extras['username']
107 repository = rc_extras['repository']
107 repository = rc_extras['repository']
108 scm = rc_extras['scm']
108 scm = rc_extras['scm']
109 locked_by = rc_extras['locked_by']
109 locked_by = rc_extras['locked_by']
110 else:
110 else:
111 raise Exception('Missing data in repo.ui and os.environ')
111 raise Exception('Missing data in repo.ui and os.environ')
112
112
113 usr = User.get_by_username(username)
113 usr = User.get_by_username(username)
114 if locked_by[0] and usr.user_id != int(locked_by[0]):
114 if locked_by[0] and usr.user_id != int(locked_by[0]):
115 locked_by = User.get(locked_by[0]).username
115 locked_by = User.get(locked_by[0]).username
116 raise HTTPLockedRC(repository, locked_by)
116 # this exception is interpreted in git/hg middlewares and based
117 # on that proper return code is server to client
118 _http_ret = HTTPLockedRC(repository, locked_by)
119 if str(_http_ret.code).startswith('2'):
120 #2xx Codes don't raise exceptions
121 sys.stdout.write(_http_ret.title)
122 else:
123 raise _http_ret
117
124
118
125
119 def pre_pull(ui, repo, **kwargs):
126 def pre_pull(ui, repo, **kwargs):
120 # pre push function, currently used to ban pushing when
127 # pre push function, currently used to ban pushing when
121 # repository is locked
128 # repository is locked
122 try:
129 try:
123 rc_extras = json.loads(os.environ.get('RC_SCM_DATA', "{}"))
130 rc_extras = json.loads(os.environ.get('RC_SCM_DATA', "{}"))
124 except:
131 except:
125 rc_extras = {}
132 rc_extras = {}
126 extras = dict(repo.ui.configitems('rhodecode_extras'))
133 extras = dict(repo.ui.configitems('rhodecode_extras'))
127 if 'username' in extras:
134 if 'username' in extras:
128 username = extras['username']
135 username = extras['username']
129 repository = extras['repository']
136 repository = extras['repository']
130 scm = extras['scm']
137 scm = extras['scm']
131 locked_by = extras['locked_by']
138 locked_by = extras['locked_by']
132 elif 'username' in rc_extras:
139 elif 'username' in rc_extras:
133 username = rc_extras['username']
140 username = rc_extras['username']
134 repository = rc_extras['repository']
141 repository = rc_extras['repository']
135 scm = rc_extras['scm']
142 scm = rc_extras['scm']
136 locked_by = rc_extras['locked_by']
143 locked_by = rc_extras['locked_by']
137 else:
144 else:
138 raise Exception('Missing data in repo.ui and os.environ')
145 raise Exception('Missing data in repo.ui and os.environ')
139
146
140 if locked_by[0]:
147 if locked_by[0]:
141 locked_by = User.get(locked_by[0]).username
148 locked_by = User.get(locked_by[0]).username
142 raise HTTPLockedRC(repository, locked_by)
149 # this exception is interpreted in git/hg middlewares and based
150 # on that proper return code is server to client
151 _http_ret = HTTPLockedRC(repository, locked_by)
152 if str(_http_ret.code).startswith('2'):
153 #2xx Codes don't raise exceptions
154 sys.stdout.write(_http_ret.title)
155 else:
156 raise _http_ret
143
157
144
158
145 def log_pull_action(ui, repo, **kwargs):
159 def log_pull_action(ui, repo, **kwargs):
146 """
160 """
147 Logs user last pull action
161 Logs user last pull action
148
162
149 :param ui:
163 :param ui:
150 :param repo:
164 :param repo:
151 """
165 """
152 try:
166 try:
153 rc_extras = json.loads(os.environ.get('RC_SCM_DATA', "{}"))
167 rc_extras = json.loads(os.environ.get('RC_SCM_DATA', "{}"))
154 except:
168 except:
155 rc_extras = {}
169 rc_extras = {}
156 extras = dict(repo.ui.configitems('rhodecode_extras'))
170 extras = dict(repo.ui.configitems('rhodecode_extras'))
157 if 'username' in extras:
171 if 'username' in extras:
158 username = extras['username']
172 username = extras['username']
159 repository = extras['repository']
173 repository = extras['repository']
160 scm = extras['scm']
174 scm = extras['scm']
161 make_lock = extras['make_lock']
175 make_lock = extras['make_lock']
176 locked_by = extras['locked_by']
162 ip = extras['ip']
177 ip = extras['ip']
163 elif 'username' in rc_extras:
178 elif 'username' in rc_extras:
164 username = rc_extras['username']
179 username = rc_extras['username']
165 repository = rc_extras['repository']
180 repository = rc_extras['repository']
166 scm = rc_extras['scm']
181 scm = rc_extras['scm']
167 make_lock = rc_extras['make_lock']
182 make_lock = rc_extras['make_lock']
183 locked_by = rc_extras['locked_by']
168 ip = rc_extras['ip']
184 ip = rc_extras['ip']
169 else:
185 else:
170 raise Exception('Missing data in repo.ui and os.environ')
186 raise Exception('Missing data in repo.ui and os.environ')
171 user = User.get_by_username(username)
187 user = User.get_by_username(username)
172 action = 'pull'
188 action = 'pull'
173 action_logger(user, action, repository, ip, commit=True)
189 action_logger(user, action, repository, ip, commit=True)
174 # extension hook call
190 # extension hook call
175 from rhodecode import EXTENSIONS
191 from rhodecode import EXTENSIONS
176 callback = getattr(EXTENSIONS, 'PULL_HOOK', None)
192 callback = getattr(EXTENSIONS, 'PULL_HOOK', None)
177
193
178 if isfunction(callback):
194 if isfunction(callback):
179 kw = {}
195 kw = {}
180 kw.update(extras)
196 kw.update(extras)
181 callback(**kw)
197 callback(**kw)
182
198
183 if make_lock is True:
199 if make_lock is True:
184 Repository.lock(Repository.get_by_repo_name(repository), user.user_id)
200 Repository.lock(Repository.get_by_repo_name(repository), user.user_id)
185 #msg = 'Made lock on repo `%s`' % repository
201 #msg = 'Made lock on repo `%s`' % repository
186 #sys.stdout.write(msg)
202 #sys.stdout.write(msg)
187
203
204 if locked_by[0]:
205 locked_by = User.get(locked_by[0]).username
206 _http_ret = HTTPLockedRC(repository, locked_by)
207 if str(_http_ret.code).startswith('2'):
208 #2xx Codes don't raise exceptions
209 sys.stdout.write(_http_ret.title)
188 return 0
210 return 0
189
211
190
212
191 def log_push_action(ui, repo, **kwargs):
213 def log_push_action(ui, repo, **kwargs):
192 """
214 """
193 Maps user last push action to new changeset id, from mercurial
215 Maps user last push action to new changeset id, from mercurial
194
216
195 :param ui:
217 :param ui:
196 :param repo: repo object containing the `ui` object
218 :param repo: repo object containing the `ui` object
197 """
219 """
198
220
199 try:
221 try:
200 rc_extras = json.loads(os.environ.get('RC_SCM_DATA', "{}"))
222 rc_extras = json.loads(os.environ.get('RC_SCM_DATA', "{}"))
201 except:
223 except:
202 rc_extras = {}
224 rc_extras = {}
203
225
204 extras = dict(repo.ui.configitems('rhodecode_extras'))
226 extras = dict(repo.ui.configitems('rhodecode_extras'))
205 if 'username' in extras:
227 if 'username' in extras:
206 username = extras['username']
228 username = extras['username']
207 repository = extras['repository']
229 repository = extras['repository']
208 scm = extras['scm']
230 scm = extras['scm']
209 make_lock = extras['make_lock']
231 make_lock = extras['make_lock']
232 locked_by = extras['locked_by']
210 action = extras['action']
233 action = extras['action']
211 elif 'username' in rc_extras:
234 elif 'username' in rc_extras:
212 username = rc_extras['username']
235 username = rc_extras['username']
213 repository = rc_extras['repository']
236 repository = rc_extras['repository']
214 scm = rc_extras['scm']
237 scm = rc_extras['scm']
215 make_lock = rc_extras['make_lock']
238 make_lock = rc_extras['make_lock']
239 locked_by = rc_extras['locked_by']
216 action = extras['action']
240 action = extras['action']
217 else:
241 else:
218 raise Exception('Missing data in repo.ui and os.environ')
242 raise Exception('Missing data in repo.ui and os.environ')
219
243
220 action = action + ':%s'
244 action = action + ':%s'
221
245
222 if scm == 'hg':
246 if scm == 'hg':
223 node = kwargs['node']
247 node = kwargs['node']
224
248
225 def get_revs(repo, rev_opt):
249 def get_revs(repo, rev_opt):
226 if rev_opt:
250 if rev_opt:
227 revs = revrange(repo, rev_opt)
251 revs = revrange(repo, rev_opt)
228
252
229 if len(revs) == 0:
253 if len(revs) == 0:
230 return (nullrev, nullrev)
254 return (nullrev, nullrev)
231 return (max(revs), min(revs))
255 return (max(revs), min(revs))
232 else:
256 else:
233 return (len(repo) - 1, 0)
257 return (len(repo) - 1, 0)
234
258
235 stop, start = get_revs(repo, [node + ':'])
259 stop, start = get_revs(repo, [node + ':'])
236 h = binascii.hexlify
260 h = binascii.hexlify
237 revs = [h(repo[r].node()) for r in xrange(start, stop + 1)]
261 revs = [h(repo[r].node()) for r in xrange(start, stop + 1)]
238 elif scm == 'git':
262 elif scm == 'git':
239 revs = kwargs.get('_git_revs', [])
263 revs = kwargs.get('_git_revs', [])
240 if '_git_revs' in kwargs:
264 if '_git_revs' in kwargs:
241 kwargs.pop('_git_revs')
265 kwargs.pop('_git_revs')
242
266
243 action = action % ','.join(revs)
267 action = action % ','.join(revs)
244
268
245 action_logger(username, action, repository, extras['ip'], commit=True)
269 action_logger(username, action, repository, extras['ip'], commit=True)
246
270
247 # extension hook call
271 # extension hook call
248 from rhodecode import EXTENSIONS
272 from rhodecode import EXTENSIONS
249 callback = getattr(EXTENSIONS, 'PUSH_HOOK', None)
273 callback = getattr(EXTENSIONS, 'PUSH_HOOK', None)
250 if isfunction(callback):
274 if isfunction(callback):
251 kw = {'pushed_revs': revs}
275 kw = {'pushed_revs': revs}
252 kw.update(extras)
276 kw.update(extras)
253 callback(**kw)
277 callback(**kw)
254
278
255 if make_lock is False:
279 if make_lock is False:
256 Repository.unlock(Repository.get_by_repo_name(repository))
280 Repository.unlock(Repository.get_by_repo_name(repository))
257 msg = 'Released lock on repo `%s`\n' % repository
281 msg = 'Released lock on repo `%s`\n' % repository
258 sys.stdout.write(msg)
282 sys.stdout.write(msg)
259
283
284 if locked_by[0]:
285 locked_by = User.get(locked_by[0]).username
286 _http_ret = HTTPLockedRC(repository, locked_by)
287 if str(_http_ret.code).startswith('2'):
288 #2xx Codes don't raise exceptions
289 sys.stdout.write(_http_ret.title)
290
260 return 0
291 return 0
261
292
262
293
263 def log_create_repository(repository_dict, created_by, **kwargs):
294 def log_create_repository(repository_dict, created_by, **kwargs):
264 """
295 """
265 Post create repository Hook. This is a dummy function for admins to re-use
296 Post create repository Hook. This is a dummy function for admins to re-use
266 if needed. It's taken from rhodecode-extensions module and executed
297 if needed. It's taken from rhodecode-extensions module and executed
267 if present
298 if present
268
299
269 :param repository: dict dump of repository object
300 :param repository: dict dump of repository object
270 :param created_by: username who created repository
301 :param created_by: username who created repository
271
302
272 available keys of repository_dict:
303 available keys of repository_dict:
273
304
274 'repo_type',
305 'repo_type',
275 'description',
306 'description',
276 'private',
307 'private',
277 'created_on',
308 'created_on',
278 'enable_downloads',
309 'enable_downloads',
279 'repo_id',
310 'repo_id',
280 'user_id',
311 'user_id',
281 'enable_statistics',
312 'enable_statistics',
282 'clone_uri',
313 'clone_uri',
283 'fork_id',
314 'fork_id',
284 'group_id',
315 'group_id',
285 'repo_name'
316 'repo_name'
286
317
287 """
318 """
288 from rhodecode import EXTENSIONS
319 from rhodecode import EXTENSIONS
289 callback = getattr(EXTENSIONS, 'CREATE_REPO_HOOK', None)
320 callback = getattr(EXTENSIONS, 'CREATE_REPO_HOOK', None)
290 if isfunction(callback):
321 if isfunction(callback):
291 kw = {}
322 kw = {}
292 kw.update(repository_dict)
323 kw.update(repository_dict)
293 kw.update({'created_by': created_by})
324 kw.update({'created_by': created_by})
294 kw.update(kwargs)
325 kw.update(kwargs)
295 return callback(**kw)
326 return callback(**kw)
296
327
297 return 0
328 return 0
298
329
299
330
300 def log_delete_repository(repository_dict, deleted_by, **kwargs):
331 def log_delete_repository(repository_dict, deleted_by, **kwargs):
301 """
332 """
302 Post delete repository Hook. This is a dummy function for admins to re-use
333 Post delete repository Hook. This is a dummy function for admins to re-use
303 if needed. It's taken from rhodecode-extensions module and executed
334 if needed. It's taken from rhodecode-extensions module and executed
304 if present
335 if present
305
336
306 :param repository: dict dump of repository object
337 :param repository: dict dump of repository object
307 :param deleted_by: username who deleted the repository
338 :param deleted_by: username who deleted the repository
308
339
309 available keys of repository_dict:
340 available keys of repository_dict:
310
341
311 'repo_type',
342 'repo_type',
312 'description',
343 'description',
313 'private',
344 'private',
314 'created_on',
345 'created_on',
315 'enable_downloads',
346 'enable_downloads',
316 'repo_id',
347 'repo_id',
317 'user_id',
348 'user_id',
318 'enable_statistics',
349 'enable_statistics',
319 'clone_uri',
350 'clone_uri',
320 'fork_id',
351 'fork_id',
321 'group_id',
352 'group_id',
322 'repo_name'
353 'repo_name'
323
354
324 """
355 """
325 from rhodecode import EXTENSIONS
356 from rhodecode import EXTENSIONS
326 callback = getattr(EXTENSIONS, 'DELETE_REPO_HOOK', None)
357 callback = getattr(EXTENSIONS, 'DELETE_REPO_HOOK', None)
327 if isfunction(callback):
358 if isfunction(callback):
328 kw = {}
359 kw = {}
329 kw.update(repository_dict)
360 kw.update(repository_dict)
330 kw.update({'deleted_by': deleted_by,
361 kw.update({'deleted_by': deleted_by,
331 'deleted_on': time.time()})
362 'deleted_on': time.time()})
332 kw.update(kwargs)
363 kw.update(kwargs)
333 return callback(**kw)
364 return callback(**kw)
334
365
335 return 0
366 return 0
336
367
337
368
338 handle_git_pre_receive = (lambda repo_path, revs, env:
369 handle_git_pre_receive = (lambda repo_path, revs, env:
339 handle_git_receive(repo_path, revs, env, hook_type='pre'))
370 handle_git_receive(repo_path, revs, env, hook_type='pre'))
340 handle_git_post_receive = (lambda repo_path, revs, env:
371 handle_git_post_receive = (lambda repo_path, revs, env:
341 handle_git_receive(repo_path, revs, env, hook_type='post'))
372 handle_git_receive(repo_path, revs, env, hook_type='post'))
342
373
343
374
344 def handle_git_receive(repo_path, revs, env, hook_type='post'):
375 def handle_git_receive(repo_path, revs, env, hook_type='post'):
345 """
376 """
346 A really hacky method that is runned by git post-receive hook and logs
377 A really hacky method that is runned by git post-receive hook and logs
347 an push action together with pushed revisions. It's executed by subprocess
378 an push action together with pushed revisions. It's executed by subprocess
348 thus needs all info to be able to create a on the fly pylons enviroment,
379 thus needs all info to be able to create a on the fly pylons enviroment,
349 connect to database and run the logging code. Hacky as sh*t but works.
380 connect to database and run the logging code. Hacky as sh*t but works.
350
381
351 :param repo_path:
382 :param repo_path:
352 :type repo_path:
383 :type repo_path:
353 :param revs:
384 :param revs:
354 :type revs:
385 :type revs:
355 :param env:
386 :param env:
356 :type env:
387 :type env:
357 """
388 """
358 from paste.deploy import appconfig
389 from paste.deploy import appconfig
359 from sqlalchemy import engine_from_config
390 from sqlalchemy import engine_from_config
360 from rhodecode.config.environment import load_environment
391 from rhodecode.config.environment import load_environment
361 from rhodecode.model import init_model
392 from rhodecode.model import init_model
362 from rhodecode.model.db import RhodeCodeUi
393 from rhodecode.model.db import RhodeCodeUi
363 from rhodecode.lib.utils import make_ui
394 from rhodecode.lib.utils import make_ui
364 extras = json.loads(env['RHODECODE_EXTRAS'])
395 extras = json.loads(env['RHODECODE_EXTRAS'])
365
396
366 path, ini_name = os.path.split(extras['config'])
397 path, ini_name = os.path.split(extras['config'])
367 conf = appconfig('config:%s' % ini_name, relative_to=path)
398 conf = appconfig('config:%s' % ini_name, relative_to=path)
368 load_environment(conf.global_conf, conf.local_conf)
399 load_environment(conf.global_conf, conf.local_conf)
369
400
370 engine = engine_from_config(conf, 'sqlalchemy.db1.')
401 engine = engine_from_config(conf, 'sqlalchemy.db1.')
371 init_model(engine)
402 init_model(engine)
372
403
373 baseui = make_ui('db')
404 baseui = make_ui('db')
374 # fix if it's not a bare repo
405 # fix if it's not a bare repo
375 if repo_path.endswith(os.sep + '.git'):
406 if repo_path.endswith(os.sep + '.git'):
376 repo_path = repo_path[:-5]
407 repo_path = repo_path[:-5]
377
408
378 repo = Repository.get_by_full_path(repo_path)
409 repo = Repository.get_by_full_path(repo_path)
379 if not repo:
410 if not repo:
380 raise OSError('Repository %s not found in database'
411 raise OSError('Repository %s not found in database'
381 % (safe_str(repo_path)))
412 % (safe_str(repo_path)))
382
413
383 _hooks = dict(baseui.configitems('hooks')) or {}
414 _hooks = dict(baseui.configitems('hooks')) or {}
384
415
385 for k, v in extras.items():
416 for k, v in extras.items():
386 baseui.setconfig('rhodecode_extras', k, v)
417 baseui.setconfig('rhodecode_extras', k, v)
387 if hook_type == 'pre':
418 if hook_type == 'pre':
388 repo = repo.scm_instance
419 repo = repo.scm_instance
389 else:
420 else:
390 #post push shouldn't use the cached instance never
421 #post push shouldn't use the cached instance never
391 repo = repo.scm_instance_no_cache
422 repo = repo.scm_instance_no_cache
392
423
393 repo.ui = baseui
424 repo.ui = baseui
394
425
395 if hook_type == 'pre':
426 if hook_type == 'pre':
396 pre_push(baseui, repo)
427 pre_push(baseui, repo)
397
428
398 # if push hook is enabled via web interface
429 # if push hook is enabled via web interface
399 elif hook_type == 'post' and _hooks.get(RhodeCodeUi.HOOK_PUSH):
430 elif hook_type == 'post' and _hooks.get(RhodeCodeUi.HOOK_PUSH):
400
431
401 rev_data = []
432 rev_data = []
402 for l in revs:
433 for l in revs:
403 old_rev, new_rev, ref = l.split(' ')
434 old_rev, new_rev, ref = l.split(' ')
404 _ref_data = ref.split('/')
435 _ref_data = ref.split('/')
405 if _ref_data[1] in ['tags', 'heads']:
436 if _ref_data[1] in ['tags', 'heads']:
406 rev_data.append({'old_rev': old_rev,
437 rev_data.append({'old_rev': old_rev,
407 'new_rev': new_rev,
438 'new_rev': new_rev,
408 'ref': ref,
439 'ref': ref,
409 'type': _ref_data[1],
440 'type': _ref_data[1],
410 'name': _ref_data[2].strip()})
441 'name': _ref_data[2].strip()})
411
442
412 git_revs = []
443 git_revs = []
413 for push_ref in rev_data:
444 for push_ref in rev_data:
414 _type = push_ref['type']
445 _type = push_ref['type']
415 if _type == 'heads':
446 if _type == 'heads':
416 if push_ref['old_rev'] == EmptyChangeset().raw_id:
447 if push_ref['old_rev'] == EmptyChangeset().raw_id:
417 cmd = "for-each-ref --format='%(refname)' 'refs/heads/*'"
448 cmd = "for-each-ref --format='%(refname)' 'refs/heads/*'"
418 heads = repo.run_git_command(cmd)[0]
449 heads = repo.run_git_command(cmd)[0]
419 heads = heads.replace(push_ref['ref'], '')
450 heads = heads.replace(push_ref['ref'], '')
420 heads = ' '.join(map(lambda c: c.strip('\n').strip(),
451 heads = ' '.join(map(lambda c: c.strip('\n').strip(),
421 heads.splitlines()))
452 heads.splitlines()))
422 cmd = (('log %(new_rev)s' % push_ref) +
453 cmd = (('log %(new_rev)s' % push_ref) +
423 ' --reverse --pretty=format:"%H" --not ' + heads)
454 ' --reverse --pretty=format:"%H" --not ' + heads)
424 git_revs += repo.run_git_command(cmd)[0].splitlines()
455 git_revs += repo.run_git_command(cmd)[0].splitlines()
425
456
426 elif push_ref['new_rev'] == EmptyChangeset().raw_id:
457 elif push_ref['new_rev'] == EmptyChangeset().raw_id:
427 #delete branch case
458 #delete branch case
428 git_revs += ['delete_branch=>%s' % push_ref['name']]
459 git_revs += ['delete_branch=>%s' % push_ref['name']]
429 else:
460 else:
430 cmd = (('log %(old_rev)s..%(new_rev)s' % push_ref) +
461 cmd = (('log %(old_rev)s..%(new_rev)s' % push_ref) +
431 ' --reverse --pretty=format:"%H"')
462 ' --reverse --pretty=format:"%H"')
432 git_revs += repo.run_git_command(cmd)[0].splitlines()
463 git_revs += repo.run_git_command(cmd)[0].splitlines()
433
464
434 elif _type == 'tags':
465 elif _type == 'tags':
435 git_revs += ['tag=>%s' % push_ref['name']]
466 git_revs += ['tag=>%s' % push_ref['name']]
436
467
437 log_push_action(baseui, repo, _git_revs=git_revs)
468 log_push_action(baseui, repo, _git_revs=git_revs)
@@ -1,341 +1,342 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.middleware.simplegit
3 rhodecode.lib.middleware.simplegit
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 SimpleGit middleware for handling git protocol request (push/clone etc.)
6 SimpleGit middleware for handling git protocol request (push/clone etc.)
7 It's implemented with basic auth function
7 It's implemented with basic auth function
8
8
9 :created_on: Apr 28, 2010
9 :created_on: Apr 28, 2010
10 :author: marcink
10 :author: marcink
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
12 :license: GPLv3, see COPYING for more details.
12 :license: GPLv3, see COPYING for more details.
13 """
13 """
14 # This program is free software: you can redistribute it and/or modify
14 # This program is free software: you can redistribute it and/or modify
15 # it under the terms of the GNU General Public License as published by
15 # it under the terms of the GNU General Public License as published by
16 # the Free Software Foundation, either version 3 of the License, or
16 # the Free Software Foundation, either version 3 of the License, or
17 # (at your option) any later version.
17 # (at your option) any later version.
18 #
18 #
19 # This program is distributed in the hope that it will be useful,
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
22 # GNU General Public License for more details.
23 #
23 #
24 # You should have received a copy of the GNU General Public License
24 # You should have received a copy of the GNU General Public License
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26
26
27 import os
27 import os
28 import re
28 import re
29 import logging
29 import logging
30 import traceback
30 import traceback
31
31
32 from dulwich import server as dulserver
32 from dulwich import server as dulserver
33 from dulwich.web import LimitedInputFilter, GunzipFilter
33 from dulwich.web import LimitedInputFilter, GunzipFilter
34 from rhodecode.lib.exceptions import HTTPLockedRC
34 from rhodecode.lib.exceptions import HTTPLockedRC
35 from rhodecode.lib.hooks import pre_pull
35 from rhodecode.lib.hooks import pre_pull
36
36
37
37
38 class SimpleGitUploadPackHandler(dulserver.UploadPackHandler):
38 class SimpleGitUploadPackHandler(dulserver.UploadPackHandler):
39
39
40 def handle(self):
40 def handle(self):
41 write = lambda x: self.proto.write_sideband(1, x)
41 write = lambda x: self.proto.write_sideband(1, x)
42
42
43 graph_walker = dulserver.ProtocolGraphWalker(self,
43 graph_walker = dulserver.ProtocolGraphWalker(self,
44 self.repo.object_store,
44 self.repo.object_store,
45 self.repo.get_peeled)
45 self.repo.get_peeled)
46 objects_iter = self.repo.fetch_objects(
46 objects_iter = self.repo.fetch_objects(
47 graph_walker.determine_wants, graph_walker, self.progress,
47 graph_walker.determine_wants, graph_walker, self.progress,
48 get_tagged=self.get_tagged)
48 get_tagged=self.get_tagged)
49
49
50 # Did the process short-circuit (e.g. in a stateless RPC call)? Note
50 # Did the process short-circuit (e.g. in a stateless RPC call)? Note
51 # that the client still expects a 0-object pack in most cases.
51 # that the client still expects a 0-object pack in most cases.
52 if objects_iter is None:
52 if objects_iter is None:
53 return
53 return
54
54
55 self.progress("counting objects: %d, done.\n" % len(objects_iter))
55 self.progress("counting objects: %d, done.\n" % len(objects_iter))
56 dulserver.write_pack_objects(dulserver.ProtocolFile(None, write),
56 dulserver.write_pack_objects(dulserver.ProtocolFile(None, write),
57 objects_iter)
57 objects_iter)
58 messages = []
58 messages = []
59 messages.append('thank you for using rhodecode')
59 messages.append('thank you for using rhodecode')
60
60
61 for msg in messages:
61 for msg in messages:
62 self.progress(msg + "\n")
62 self.progress(msg + "\n")
63 # we are done
63 # we are done
64 self.proto.write("0000")
64 self.proto.write("0000")
65
65
66
66
67 dulserver.DEFAULT_HANDLERS = {
67 dulserver.DEFAULT_HANDLERS = {
68 #git-ls-remote, git-clone, git-fetch and git-pull
68 #git-ls-remote, git-clone, git-fetch and git-pull
69 'git-upload-pack': SimpleGitUploadPackHandler,
69 'git-upload-pack': SimpleGitUploadPackHandler,
70 #git-push
70 #git-push
71 'git-receive-pack': dulserver.ReceivePackHandler,
71 'git-receive-pack': dulserver.ReceivePackHandler,
72 }
72 }
73
73
74 # not used for now until dulwich get's fixed
74 # not used for now until dulwich get's fixed
75 #from dulwich.repo import Repo
75 #from dulwich.repo import Repo
76 #from dulwich.web import make_wsgi_chain
76 #from dulwich.web import make_wsgi_chain
77
77
78 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
78 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
79 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError, \
79 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError, \
80 HTTPBadRequest, HTTPNotAcceptable
80 HTTPBadRequest, HTTPNotAcceptable
81
81
82 from rhodecode.lib.utils2 import safe_str, fix_PATH, get_server_url
82 from rhodecode.lib.utils2 import safe_str, fix_PATH, get_server_url
83 from rhodecode.lib.base import BaseVCSController
83 from rhodecode.lib.base import BaseVCSController
84 from rhodecode.lib.auth import get_container_username
84 from rhodecode.lib.auth import get_container_username
85 from rhodecode.lib.utils import is_valid_repo, make_ui
85 from rhodecode.lib.utils import is_valid_repo, make_ui
86 from rhodecode.lib.compat import json
86 from rhodecode.lib.compat import json
87 from rhodecode.model.db import User, RhodeCodeUi
87 from rhodecode.model.db import User, RhodeCodeUi
88
88
89 log = logging.getLogger(__name__)
89 log = logging.getLogger(__name__)
90
90
91
91
92 GIT_PROTO_PAT = re.compile(r'^/(.+)/(info/refs|git-upload-pack|git-receive-pack)')
92 GIT_PROTO_PAT = re.compile(r'^/(.+)/(info/refs|git-upload-pack|git-receive-pack)')
93
93
94
94
95 def is_git(environ):
95 def is_git(environ):
96 path_info = environ['PATH_INFO']
96 path_info = environ['PATH_INFO']
97 isgit_path = GIT_PROTO_PAT.match(path_info)
97 isgit_path = GIT_PROTO_PAT.match(path_info)
98 log.debug('pathinfo: %s detected as GIT %s' % (
98 log.debug('pathinfo: %s detected as GIT %s' % (
99 path_info, isgit_path != None)
99 path_info, isgit_path != None)
100 )
100 )
101 return isgit_path
101 return isgit_path
102
102
103
103
104 class SimpleGit(BaseVCSController):
104 class SimpleGit(BaseVCSController):
105
105
106 def _handle_request(self, environ, start_response):
106 def _handle_request(self, environ, start_response):
107 if not is_git(environ):
107 if not is_git(environ):
108 return self.application(environ, start_response)
108 return self.application(environ, start_response)
109 if not self._check_ssl(environ, start_response):
109 if not self._check_ssl(environ, start_response):
110 return HTTPNotAcceptable('SSL REQUIRED !')(environ, start_response)
110 return HTTPNotAcceptable('SSL REQUIRED !')(environ, start_response)
111
111
112 ip_addr = self._get_ip_addr(environ)
112 ip_addr = self._get_ip_addr(environ)
113 username = None
113 username = None
114 self._git_first_op = False
114 self._git_first_op = False
115 # skip passing error to error controller
115 # skip passing error to error controller
116 environ['pylons.status_code_redirect'] = True
116 environ['pylons.status_code_redirect'] = True
117
117
118 #======================================================================
118 #======================================================================
119 # EXTRACT REPOSITORY NAME FROM ENV
119 # EXTRACT REPOSITORY NAME FROM ENV
120 #======================================================================
120 #======================================================================
121 try:
121 try:
122 repo_name = self.__get_repository(environ)
122 repo_name = self.__get_repository(environ)
123 log.debug('Extracted repo name is %s' % repo_name)
123 log.debug('Extracted repo name is %s' % repo_name)
124 except:
124 except:
125 return HTTPInternalServerError()(environ, start_response)
125 return HTTPInternalServerError()(environ, start_response)
126
126
127 # quick check if that dir exists...
127 # quick check if that dir exists...
128 if is_valid_repo(repo_name, self.basepath, 'git') is False:
128 if is_valid_repo(repo_name, self.basepath, 'git') is False:
129 return HTTPNotFound()(environ, start_response)
129 return HTTPNotFound()(environ, start_response)
130
130
131 #======================================================================
131 #======================================================================
132 # GET ACTION PULL or PUSH
132 # GET ACTION PULL or PUSH
133 #======================================================================
133 #======================================================================
134 action = self.__get_action(environ)
134 action = self.__get_action(environ)
135
135
136 #======================================================================
136 #======================================================================
137 # CHECK ANONYMOUS PERMISSION
137 # CHECK ANONYMOUS PERMISSION
138 #======================================================================
138 #======================================================================
139 if action in ['pull', 'push']:
139 if action in ['pull', 'push']:
140 anonymous_user = self.__get_user('default')
140 anonymous_user = self.__get_user('default')
141 username = anonymous_user.username
141 username = anonymous_user.username
142 anonymous_perm = self._check_permission(action, anonymous_user,
142 anonymous_perm = self._check_permission(action, anonymous_user,
143 repo_name, ip_addr)
143 repo_name, ip_addr)
144
144
145 if anonymous_perm is not True or anonymous_user.active is False:
145 if anonymous_perm is not True or anonymous_user.active is False:
146 if anonymous_perm is not True:
146 if anonymous_perm is not True:
147 log.debug('Not enough credentials to access this '
147 log.debug('Not enough credentials to access this '
148 'repository as anonymous user')
148 'repository as anonymous user')
149 if anonymous_user.active is False:
149 if anonymous_user.active is False:
150 log.debug('Anonymous access is disabled, running '
150 log.debug('Anonymous access is disabled, running '
151 'authentication')
151 'authentication')
152 #==============================================================
152 #==============================================================
153 # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
153 # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
154 # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
154 # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
155 #==============================================================
155 #==============================================================
156
156
157 # Attempting to retrieve username from the container
157 # Attempting to retrieve username from the container
158 username = get_container_username(environ, self.config)
158 username = get_container_username(environ, self.config)
159
159
160 # If not authenticated by the container, running basic auth
160 # If not authenticated by the container, running basic auth
161 if not username:
161 if not username:
162 self.authenticate.realm = \
162 self.authenticate.realm = \
163 safe_str(self.config['rhodecode_realm'])
163 safe_str(self.config['rhodecode_realm'])
164 result = self.authenticate(environ)
164 result = self.authenticate(environ)
165 if isinstance(result, str):
165 if isinstance(result, str):
166 AUTH_TYPE.update(environ, 'basic')
166 AUTH_TYPE.update(environ, 'basic')
167 REMOTE_USER.update(environ, result)
167 REMOTE_USER.update(environ, result)
168 username = result
168 username = result
169 else:
169 else:
170 return result.wsgi_application(environ, start_response)
170 return result.wsgi_application(environ, start_response)
171
171
172 #==============================================================
172 #==============================================================
173 # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
173 # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
174 #==============================================================
174 #==============================================================
175 try:
175 try:
176 user = self.__get_user(username)
176 user = self.__get_user(username)
177 if user is None or not user.active:
177 if user is None or not user.active:
178 return HTTPForbidden()(environ, start_response)
178 return HTTPForbidden()(environ, start_response)
179 username = user.username
179 username = user.username
180 except:
180 except:
181 log.error(traceback.format_exc())
181 log.error(traceback.format_exc())
182 return HTTPInternalServerError()(environ, start_response)
182 return HTTPInternalServerError()(environ, start_response)
183
183
184 #check permissions for this repository
184 #check permissions for this repository
185 perm = self._check_permission(action, user, repo_name, ip_addr)
185 perm = self._check_permission(action, user, repo_name, ip_addr)
186 if perm is not True:
186 if perm is not True:
187 return HTTPForbidden()(environ, start_response)
187 return HTTPForbidden()(environ, start_response)
188
188
189 # extras are injected into UI object and later available
189 # extras are injected into UI object and later available
190 # in hooks executed by rhodecode
190 # in hooks executed by rhodecode
191 from rhodecode import CONFIG
191 from rhodecode import CONFIG
192 server_url = get_server_url(environ)
192 server_url = get_server_url(environ)
193 extras = {
193 extras = {
194 'ip': ip_addr,
194 'ip': ip_addr,
195 'username': username,
195 'username': username,
196 'action': action,
196 'action': action,
197 'repository': repo_name,
197 'repository': repo_name,
198 'scm': 'git',
198 'scm': 'git',
199 'config': CONFIG['__file__'],
199 'config': CONFIG['__file__'],
200 'server_url': server_url,
200 'server_url': server_url,
201 'make_lock': None,
201 'make_lock': None,
202 'locked_by': [None, None]
202 'locked_by': [None, None]
203 }
203 }
204
204
205 #===================================================================
205 #===================================================================
206 # GIT REQUEST HANDLING
206 # GIT REQUEST HANDLING
207 #===================================================================
207 #===================================================================
208 repo_path = os.path.join(safe_str(self.basepath), safe_str(repo_name))
208 repo_path = os.path.join(safe_str(self.basepath), safe_str(repo_name))
209 log.debug('Repository path is %s' % repo_path)
209 log.debug('Repository path is %s' % repo_path)
210
210
211 # CHECK LOCKING only if it's not ANONYMOUS USER
211 # CHECK LOCKING only if it's not ANONYMOUS USER
212 if username != User.DEFAULT_USER:
212 if username != User.DEFAULT_USER:
213 log.debug('Checking locking on repository')
213 log.debug('Checking locking on repository')
214 (make_lock,
214 (make_lock,
215 locked,
215 locked,
216 locked_by) = self._check_locking_state(
216 locked_by) = self._check_locking_state(
217 environ=environ, action=action,
217 environ=environ, action=action,
218 repo=repo_name, user_id=user.user_id
218 repo=repo_name, user_id=user.user_id
219 )
219 )
220 # store the make_lock for later evaluation in hooks
220 # store the make_lock for later evaluation in hooks
221 extras.update({'make_lock': make_lock,
221 extras.update({'make_lock': make_lock,
222 'locked_by': locked_by})
222 'locked_by': locked_by})
223 # set the environ variables for this request
223 # set the environ variables for this request
224 os.environ['RC_SCM_DATA'] = json.dumps(extras)
224 os.environ['RC_SCM_DATA'] = json.dumps(extras)
225 fix_PATH()
225 fix_PATH()
226 log.debug('HOOKS extras is %s' % extras)
226 log.debug('HOOKS extras is %s' % extras)
227 baseui = make_ui('db')
227 baseui = make_ui('db')
228 self.__inject_extras(repo_path, baseui, extras)
228 self.__inject_extras(repo_path, baseui, extras)
229
229
230 try:
230 try:
231 self._handle_githooks(repo_name, action, baseui, environ)
231 self._handle_githooks(repo_name, action, baseui, environ)
232 log.info('%s action on GIT repo "%s" by "%s" from %s' %
232 log.info('%s action on GIT repo "%s" by "%s" from %s' %
233 (action, repo_name, username, ip_addr))
233 (action, repo_name, username, ip_addr))
234 app = self.__make_app(repo_name, repo_path, extras)
234 app = self.__make_app(repo_name, repo_path, extras)
235 return app(environ, start_response)
235 return app(environ, start_response)
236 except HTTPLockedRC, e:
236 except HTTPLockedRC, e:
237 log.debug('Repository LOCKED ret code 423!')
237 _code = CONFIG.get('lock_ret_code')
238 log.debug('Repository LOCKED ret code %s!' % (_code))
238 return e(environ, start_response)
239 return e(environ, start_response)
239 except Exception:
240 except Exception:
240 log.error(traceback.format_exc())
241 log.error(traceback.format_exc())
241 return HTTPInternalServerError()(environ, start_response)
242 return HTTPInternalServerError()(environ, start_response)
242 finally:
243 finally:
243 # invalidate cache on push
244 # invalidate cache on push
244 if action == 'push':
245 if action == 'push':
245 self._invalidate_cache(repo_name)
246 self._invalidate_cache(repo_name)
246
247
247 def __make_app(self, repo_name, repo_path, extras):
248 def __make_app(self, repo_name, repo_path, extras):
248 """
249 """
249 Make an wsgi application using dulserver
250 Make an wsgi application using dulserver
250
251
251 :param repo_name: name of the repository
252 :param repo_name: name of the repository
252 :param repo_path: full path to the repository
253 :param repo_path: full path to the repository
253 """
254 """
254
255
255 from rhodecode.lib.middleware.pygrack import make_wsgi_app
256 from rhodecode.lib.middleware.pygrack import make_wsgi_app
256 app = make_wsgi_app(
257 app = make_wsgi_app(
257 repo_root=safe_str(self.basepath),
258 repo_root=safe_str(self.basepath),
258 repo_name=repo_name,
259 repo_name=repo_name,
259 extras=extras,
260 extras=extras,
260 )
261 )
261 app = GunzipFilter(LimitedInputFilter(app))
262 app = GunzipFilter(LimitedInputFilter(app))
262 return app
263 return app
263
264
264 def __get_repository(self, environ):
265 def __get_repository(self, environ):
265 """
266 """
266 Get's repository name out of PATH_INFO header
267 Get's repository name out of PATH_INFO header
267
268
268 :param environ: environ where PATH_INFO is stored
269 :param environ: environ where PATH_INFO is stored
269 """
270 """
270 try:
271 try:
271 environ['PATH_INFO'] = self._get_by_id(environ['PATH_INFO'])
272 environ['PATH_INFO'] = self._get_by_id(environ['PATH_INFO'])
272 repo_name = GIT_PROTO_PAT.match(environ['PATH_INFO']).group(1)
273 repo_name = GIT_PROTO_PAT.match(environ['PATH_INFO']).group(1)
273 except:
274 except:
274 log.error(traceback.format_exc())
275 log.error(traceback.format_exc())
275 raise
276 raise
276
277
277 return repo_name
278 return repo_name
278
279
279 def __get_user(self, username):
280 def __get_user(self, username):
280 return User.get_by_username(username)
281 return User.get_by_username(username)
281
282
282 def __get_action(self, environ):
283 def __get_action(self, environ):
283 """
284 """
284 Maps git request commands into a pull or push command.
285 Maps git request commands into a pull or push command.
285
286
286 :param environ:
287 :param environ:
287 """
288 """
288 service = environ['QUERY_STRING'].split('=')
289 service = environ['QUERY_STRING'].split('=')
289
290
290 if len(service) > 1:
291 if len(service) > 1:
291 service_cmd = service[1]
292 service_cmd = service[1]
292 mapping = {
293 mapping = {
293 'git-receive-pack': 'push',
294 'git-receive-pack': 'push',
294 'git-upload-pack': 'pull',
295 'git-upload-pack': 'pull',
295 }
296 }
296 op = mapping[service_cmd]
297 op = mapping[service_cmd]
297 self._git_stored_op = op
298 self._git_stored_op = op
298 return op
299 return op
299 else:
300 else:
300 # try to fallback to stored variable as we don't know if the last
301 # try to fallback to stored variable as we don't know if the last
301 # operation is pull/push
302 # operation is pull/push
302 op = getattr(self, '_git_stored_op', 'pull')
303 op = getattr(self, '_git_stored_op', 'pull')
303 return op
304 return op
304
305
305 def _handle_githooks(self, repo_name, action, baseui, environ):
306 def _handle_githooks(self, repo_name, action, baseui, environ):
306 """
307 """
307 Handles pull action, push is handled by post-receive hook
308 Handles pull action, push is handled by post-receive hook
308 """
309 """
309 from rhodecode.lib.hooks import log_pull_action
310 from rhodecode.lib.hooks import log_pull_action
310 service = environ['QUERY_STRING'].split('=')
311 service = environ['QUERY_STRING'].split('=')
311
312
312 if len(service) < 2:
313 if len(service) < 2:
313 return
314 return
314
315
315 from rhodecode.model.db import Repository
316 from rhodecode.model.db import Repository
316 _repo = Repository.get_by_repo_name(repo_name)
317 _repo = Repository.get_by_repo_name(repo_name)
317 _repo = _repo.scm_instance
318 _repo = _repo.scm_instance
318 _repo._repo.ui = baseui
319 _repo._repo.ui = baseui
319
320
320 _hooks = dict(baseui.configitems('hooks')) or {}
321 _hooks = dict(baseui.configitems('hooks')) or {}
321 if action == 'pull':
322 if action == 'pull':
322 # stupid git, emulate pre-pull hook !
323 # stupid git, emulate pre-pull hook !
323 pre_pull(ui=baseui, repo=_repo._repo)
324 pre_pull(ui=baseui, repo=_repo._repo)
324 if action == 'pull' and _hooks.get(RhodeCodeUi.HOOK_PULL):
325 if action == 'pull' and _hooks.get(RhodeCodeUi.HOOK_PULL):
325 log_pull_action(ui=baseui, repo=_repo._repo)
326 log_pull_action(ui=baseui, repo=_repo._repo)
326
327
327 def __inject_extras(self, repo_path, baseui, extras={}):
328 def __inject_extras(self, repo_path, baseui, extras={}):
328 """
329 """
329 Injects some extra params into baseui instance
330 Injects some extra params into baseui instance
330
331
331 :param baseui: baseui instance
332 :param baseui: baseui instance
332 :param extras: dict with extra params to put into baseui
333 :param extras: dict with extra params to put into baseui
333 """
334 """
334
335
335 # make our hgweb quiet so it doesn't print output
336 # make our hgweb quiet so it doesn't print output
336 baseui.setconfig('ui', 'quiet', 'true')
337 baseui.setconfig('ui', 'quiet', 'true')
337
338
338 #inject some additional parameters that will be available in ui
339 #inject some additional parameters that will be available in ui
339 #for hooks
340 #for hooks
340 for k, v in extras.items():
341 for k, v in extras.items():
341 baseui.setconfig('rhodecode_extras', k, v)
342 baseui.setconfig('rhodecode_extras', k, v)
@@ -1,289 +1,290 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.middleware.simplehg
3 rhodecode.lib.middleware.simplehg
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 SimpleHG middleware for handling mercurial protocol request
6 SimpleHG middleware for handling mercurial protocol request
7 (push/clone etc.). It's implemented with basic auth function
7 (push/clone etc.). It's implemented with basic auth function
8
8
9 :created_on: Apr 28, 2010
9 :created_on: Apr 28, 2010
10 :author: marcink
10 :author: marcink
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
12 :license: GPLv3, see COPYING for more details.
12 :license: GPLv3, see COPYING for more details.
13 """
13 """
14 # This program is free software: you can redistribute it and/or modify
14 # This program is free software: you can redistribute it and/or modify
15 # it under the terms of the GNU General Public License as published by
15 # it under the terms of the GNU General Public License as published by
16 # the Free Software Foundation, either version 3 of the License, or
16 # the Free Software Foundation, either version 3 of the License, or
17 # (at your option) any later version.
17 # (at your option) any later version.
18 #
18 #
19 # This program is distributed in the hope that it will be useful,
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
22 # GNU General Public License for more details.
23 #
23 #
24 # You should have received a copy of the GNU General Public License
24 # You should have received a copy of the GNU General Public License
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26
26
27 import os
27 import os
28 import logging
28 import logging
29 import traceback
29 import traceback
30
30
31 from mercurial.error import RepoError
31 from mercurial.error import RepoError
32 from mercurial.hgweb import hgweb_mod
32 from mercurial.hgweb import hgweb_mod
33
33
34 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
34 from paste.httpheaders import REMOTE_USER, AUTH_TYPE
35 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError, \
35 from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError, \
36 HTTPBadRequest, HTTPNotAcceptable
36 HTTPBadRequest, HTTPNotAcceptable
37
37
38 from rhodecode.lib.utils2 import safe_str, fix_PATH, get_server_url
38 from rhodecode.lib.utils2 import safe_str, fix_PATH, get_server_url
39 from rhodecode.lib.base import BaseVCSController
39 from rhodecode.lib.base import BaseVCSController
40 from rhodecode.lib.auth import get_container_username
40 from rhodecode.lib.auth import get_container_username
41 from rhodecode.lib.utils import make_ui, is_valid_repo, ui_sections
41 from rhodecode.lib.utils import make_ui, is_valid_repo, ui_sections
42 from rhodecode.lib.compat import json
42 from rhodecode.lib.compat import json
43 from rhodecode.model.db import User
43 from rhodecode.model.db import User
44 from rhodecode.lib.exceptions import HTTPLockedRC
44 from rhodecode.lib.exceptions import HTTPLockedRC
45
45
46
46
47 log = logging.getLogger(__name__)
47 log = logging.getLogger(__name__)
48
48
49
49
50 def is_mercurial(environ):
50 def is_mercurial(environ):
51 """
51 """
52 Returns True if request's target is mercurial server - header
52 Returns True if request's target is mercurial server - header
53 ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
53 ``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
54 """
54 """
55 http_accept = environ.get('HTTP_ACCEPT')
55 http_accept = environ.get('HTTP_ACCEPT')
56 path_info = environ['PATH_INFO']
56 path_info = environ['PATH_INFO']
57 if http_accept and http_accept.startswith('application/mercurial'):
57 if http_accept and http_accept.startswith('application/mercurial'):
58 ishg_path = True
58 ishg_path = True
59 else:
59 else:
60 ishg_path = False
60 ishg_path = False
61
61
62 log.debug('pathinfo: %s detected as HG %s' % (
62 log.debug('pathinfo: %s detected as HG %s' % (
63 path_info, ishg_path)
63 path_info, ishg_path)
64 )
64 )
65 return ishg_path
65 return ishg_path
66
66
67
67
68 class SimpleHg(BaseVCSController):
68 class SimpleHg(BaseVCSController):
69
69
70 def _handle_request(self, environ, start_response):
70 def _handle_request(self, environ, start_response):
71 if not is_mercurial(environ):
71 if not is_mercurial(environ):
72 return self.application(environ, start_response)
72 return self.application(environ, start_response)
73 if not self._check_ssl(environ, start_response):
73 if not self._check_ssl(environ, start_response):
74 return HTTPNotAcceptable('SSL REQUIRED !')(environ, start_response)
74 return HTTPNotAcceptable('SSL REQUIRED !')(environ, start_response)
75
75
76 ip_addr = self._get_ip_addr(environ)
76 ip_addr = self._get_ip_addr(environ)
77 username = None
77 username = None
78 # skip passing error to error controller
78 # skip passing error to error controller
79 environ['pylons.status_code_redirect'] = True
79 environ['pylons.status_code_redirect'] = True
80
80
81 #======================================================================
81 #======================================================================
82 # EXTRACT REPOSITORY NAME FROM ENV
82 # EXTRACT REPOSITORY NAME FROM ENV
83 #======================================================================
83 #======================================================================
84 try:
84 try:
85 repo_name = environ['REPO_NAME'] = self.__get_repository(environ)
85 repo_name = environ['REPO_NAME'] = self.__get_repository(environ)
86 log.debug('Extracted repo name is %s' % repo_name)
86 log.debug('Extracted repo name is %s' % repo_name)
87 except:
87 except:
88 return HTTPInternalServerError()(environ, start_response)
88 return HTTPInternalServerError()(environ, start_response)
89
89
90 # quick check if that dir exists...
90 # quick check if that dir exists...
91 if is_valid_repo(repo_name, self.basepath, 'hg') is False:
91 if is_valid_repo(repo_name, self.basepath, 'hg') is False:
92 return HTTPNotFound()(environ, start_response)
92 return HTTPNotFound()(environ, start_response)
93
93
94 #======================================================================
94 #======================================================================
95 # GET ACTION PULL or PUSH
95 # GET ACTION PULL or PUSH
96 #======================================================================
96 #======================================================================
97 action = self.__get_action(environ)
97 action = self.__get_action(environ)
98
98
99 #======================================================================
99 #======================================================================
100 # CHECK ANONYMOUS PERMISSION
100 # CHECK ANONYMOUS PERMISSION
101 #======================================================================
101 #======================================================================
102 if action in ['pull', 'push']:
102 if action in ['pull', 'push']:
103 anonymous_user = self.__get_user('default')
103 anonymous_user = self.__get_user('default')
104 username = anonymous_user.username
104 username = anonymous_user.username
105 anonymous_perm = self._check_permission(action, anonymous_user,
105 anonymous_perm = self._check_permission(action, anonymous_user,
106 repo_name, ip_addr)
106 repo_name, ip_addr)
107
107
108 if anonymous_perm is not True or anonymous_user.active is False:
108 if anonymous_perm is not True or anonymous_user.active is False:
109 if anonymous_perm is not True:
109 if anonymous_perm is not True:
110 log.debug('Not enough credentials to access this '
110 log.debug('Not enough credentials to access this '
111 'repository as anonymous user')
111 'repository as anonymous user')
112 if anonymous_user.active is False:
112 if anonymous_user.active is False:
113 log.debug('Anonymous access is disabled, running '
113 log.debug('Anonymous access is disabled, running '
114 'authentication')
114 'authentication')
115 #==============================================================
115 #==============================================================
116 # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
116 # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
117 # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
117 # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
118 #==============================================================
118 #==============================================================
119
119
120 # Attempting to retrieve username from the container
120 # Attempting to retrieve username from the container
121 username = get_container_username(environ, self.config)
121 username = get_container_username(environ, self.config)
122
122
123 # If not authenticated by the container, running basic auth
123 # If not authenticated by the container, running basic auth
124 if not username:
124 if not username:
125 self.authenticate.realm = \
125 self.authenticate.realm = \
126 safe_str(self.config['rhodecode_realm'])
126 safe_str(self.config['rhodecode_realm'])
127 result = self.authenticate(environ)
127 result = self.authenticate(environ)
128 if isinstance(result, str):
128 if isinstance(result, str):
129 AUTH_TYPE.update(environ, 'basic')
129 AUTH_TYPE.update(environ, 'basic')
130 REMOTE_USER.update(environ, result)
130 REMOTE_USER.update(environ, result)
131 username = result
131 username = result
132 else:
132 else:
133 return result.wsgi_application(environ, start_response)
133 return result.wsgi_application(environ, start_response)
134
134
135 #==============================================================
135 #==============================================================
136 # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
136 # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
137 #==============================================================
137 #==============================================================
138 try:
138 try:
139 user = self.__get_user(username)
139 user = self.__get_user(username)
140 if user is None or not user.active:
140 if user is None or not user.active:
141 return HTTPForbidden()(environ, start_response)
141 return HTTPForbidden()(environ, start_response)
142 username = user.username
142 username = user.username
143 except:
143 except:
144 log.error(traceback.format_exc())
144 log.error(traceback.format_exc())
145 return HTTPInternalServerError()(environ, start_response)
145 return HTTPInternalServerError()(environ, start_response)
146
146
147 #check permissions for this repository
147 #check permissions for this repository
148 perm = self._check_permission(action, user, repo_name, ip_addr)
148 perm = self._check_permission(action, user, repo_name, ip_addr)
149 if perm is not True:
149 if perm is not True:
150 return HTTPForbidden()(environ, start_response)
150 return HTTPForbidden()(environ, start_response)
151
151
152 # extras are injected into mercurial UI object and later available
152 # extras are injected into mercurial UI object and later available
153 # in hg hooks executed by rhodecode
153 # in hg hooks executed by rhodecode
154 from rhodecode import CONFIG
154 from rhodecode import CONFIG
155 server_url = get_server_url(environ)
155 server_url = get_server_url(environ)
156 extras = {
156 extras = {
157 'ip': ip_addr,
157 'ip': ip_addr,
158 'username': username,
158 'username': username,
159 'action': action,
159 'action': action,
160 'repository': repo_name,
160 'repository': repo_name,
161 'scm': 'hg',
161 'scm': 'hg',
162 'config': CONFIG['__file__'],
162 'config': CONFIG['__file__'],
163 'server_url': server_url,
163 'server_url': server_url,
164 'make_lock': None,
164 'make_lock': None,
165 'locked_by': [None, None]
165 'locked_by': [None, None]
166 }
166 }
167 #======================================================================
167 #======================================================================
168 # MERCURIAL REQUEST HANDLING
168 # MERCURIAL REQUEST HANDLING
169 #======================================================================
169 #======================================================================
170 repo_path = os.path.join(safe_str(self.basepath), safe_str(repo_name))
170 repo_path = os.path.join(safe_str(self.basepath), safe_str(repo_name))
171 log.debug('Repository path is %s' % repo_path)
171 log.debug('Repository path is %s' % repo_path)
172
172
173 # CHECK LOCKING only if it's not ANONYMOUS USER
173 # CHECK LOCKING only if it's not ANONYMOUS USER
174 if username != User.DEFAULT_USER:
174 if username != User.DEFAULT_USER:
175 log.debug('Checking locking on repository')
175 log.debug('Checking locking on repository')
176 (make_lock,
176 (make_lock,
177 locked,
177 locked,
178 locked_by) = self._check_locking_state(
178 locked_by) = self._check_locking_state(
179 environ=environ, action=action,
179 environ=environ, action=action,
180 repo=repo_name, user_id=user.user_id
180 repo=repo_name, user_id=user.user_id
181 )
181 )
182 # store the make_lock for later evaluation in hooks
182 # store the make_lock for later evaluation in hooks
183 extras.update({'make_lock': make_lock,
183 extras.update({'make_lock': make_lock,
184 'locked_by': locked_by})
184 'locked_by': locked_by})
185
185
186 # set the environ variables for this request
186 # set the environ variables for this request
187 os.environ['RC_SCM_DATA'] = json.dumps(extras)
187 os.environ['RC_SCM_DATA'] = json.dumps(extras)
188 fix_PATH()
188 fix_PATH()
189 log.debug('HOOKS extras is %s' % extras)
189 log.debug('HOOKS extras is %s' % extras)
190 baseui = make_ui('db')
190 baseui = make_ui('db')
191 self.__inject_extras(repo_path, baseui, extras)
191 self.__inject_extras(repo_path, baseui, extras)
192
192
193 try:
193 try:
194 log.info('%s action on HG repo "%s" by "%s" from %s' %
194 log.info('%s action on HG repo "%s" by "%s" from %s' %
195 (action, repo_name, username, ip_addr))
195 (action, repo_name, username, ip_addr))
196 app = self.__make_app(repo_path, baseui, extras)
196 app = self.__make_app(repo_path, baseui, extras)
197 return app(environ, start_response)
197 return app(environ, start_response)
198 except RepoError, e:
198 except RepoError, e:
199 if str(e).find('not found') != -1:
199 if str(e).find('not found') != -1:
200 return HTTPNotFound()(environ, start_response)
200 return HTTPNotFound()(environ, start_response)
201 except HTTPLockedRC, e:
201 except HTTPLockedRC, e:
202 log.debug('Repository LOCKED ret code 423!')
202 _code = CONFIG.get('lock_ret_code')
203 log.debug('Repository LOCKED ret code %s!' % (_code))
203 return e(environ, start_response)
204 return e(environ, start_response)
204 except Exception:
205 except Exception:
205 log.error(traceback.format_exc())
206 log.error(traceback.format_exc())
206 return HTTPInternalServerError()(environ, start_response)
207 return HTTPInternalServerError()(environ, start_response)
207 finally:
208 finally:
208 # invalidate cache on push
209 # invalidate cache on push
209 if action == 'push':
210 if action == 'push':
210 self._invalidate_cache(repo_name)
211 self._invalidate_cache(repo_name)
211
212
212 def __make_app(self, repo_name, baseui, extras):
213 def __make_app(self, repo_name, baseui, extras):
213 """
214 """
214 Make an wsgi application using hgweb, and inject generated baseui
215 Make an wsgi application using hgweb, and inject generated baseui
215 instance, additionally inject some extras into ui object
216 instance, additionally inject some extras into ui object
216 """
217 """
217 return hgweb_mod.hgweb(repo_name, name=repo_name, baseui=baseui)
218 return hgweb_mod.hgweb(repo_name, name=repo_name, baseui=baseui)
218
219
219 def __get_repository(self, environ):
220 def __get_repository(self, environ):
220 """
221 """
221 Get's repository name out of PATH_INFO header
222 Get's repository name out of PATH_INFO header
222
223
223 :param environ: environ where PATH_INFO is stored
224 :param environ: environ where PATH_INFO is stored
224 """
225 """
225 try:
226 try:
226 environ['PATH_INFO'] = self._get_by_id(environ['PATH_INFO'])
227 environ['PATH_INFO'] = self._get_by_id(environ['PATH_INFO'])
227 repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
228 repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
228 if repo_name.endswith('/'):
229 if repo_name.endswith('/'):
229 repo_name = repo_name.rstrip('/')
230 repo_name = repo_name.rstrip('/')
230 except:
231 except:
231 log.error(traceback.format_exc())
232 log.error(traceback.format_exc())
232 raise
233 raise
233
234
234 return repo_name
235 return repo_name
235
236
236 def __get_user(self, username):
237 def __get_user(self, username):
237 return User.get_by_username(username)
238 return User.get_by_username(username)
238
239
239 def __get_action(self, environ):
240 def __get_action(self, environ):
240 """
241 """
241 Maps mercurial request commands into a clone,pull or push command.
242 Maps mercurial request commands into a clone,pull or push command.
242 This should always return a valid command string
243 This should always return a valid command string
243
244
244 :param environ:
245 :param environ:
245 """
246 """
246 mapping = {'changegroup': 'pull',
247 mapping = {'changegroup': 'pull',
247 'changegroupsubset': 'pull',
248 'changegroupsubset': 'pull',
248 'stream_out': 'pull',
249 'stream_out': 'pull',
249 'listkeys': 'pull',
250 'listkeys': 'pull',
250 'unbundle': 'push',
251 'unbundle': 'push',
251 'pushkey': 'push', }
252 'pushkey': 'push', }
252 for qry in environ['QUERY_STRING'].split('&'):
253 for qry in environ['QUERY_STRING'].split('&'):
253 if qry.startswith('cmd'):
254 if qry.startswith('cmd'):
254 cmd = qry.split('=')[-1]
255 cmd = qry.split('=')[-1]
255 if cmd in mapping:
256 if cmd in mapping:
256 return mapping[cmd]
257 return mapping[cmd]
257
258
258 return 'pull'
259 return 'pull'
259
260
260 raise Exception('Unable to detect pull/push action !!'
261 raise Exception('Unable to detect pull/push action !!'
261 'Are you using non standard command or client ?')
262 'Are you using non standard command or client ?')
262
263
263 def __inject_extras(self, repo_path, baseui, extras={}):
264 def __inject_extras(self, repo_path, baseui, extras={}):
264 """
265 """
265 Injects some extra params into baseui instance
266 Injects some extra params into baseui instance
266
267
267 also overwrites global settings with those takes from local hgrc file
268 also overwrites global settings with those takes from local hgrc file
268
269
269 :param baseui: baseui instance
270 :param baseui: baseui instance
270 :param extras: dict with extra params to put into baseui
271 :param extras: dict with extra params to put into baseui
271 """
272 """
272
273
273 hgrc = os.path.join(repo_path, '.hg', 'hgrc')
274 hgrc = os.path.join(repo_path, '.hg', 'hgrc')
274
275
275 # make our hgweb quiet so it doesn't print output
276 # make our hgweb quiet so it doesn't print output
276 baseui.setconfig('ui', 'quiet', 'true')
277 baseui.setconfig('ui', 'quiet', 'true')
277
278
278 #inject some additional parameters that will be available in ui
279 #inject some additional parameters that will be available in ui
279 #for hooks
280 #for hooks
280 for k, v in extras.items():
281 for k, v in extras.items():
281 baseui.setconfig('rhodecode_extras', k, v)
282 baseui.setconfig('rhodecode_extras', k, v)
282
283
283 repoui = make_ui('file', hgrc, False)
284 repoui = make_ui('file', hgrc, False)
284
285
285 if repoui:
286 if repoui:
286 #overwrite our ui instance with the section from hgrc file
287 #overwrite our ui instance with the section from hgrc file
287 for section in ui_sections:
288 for section in ui_sections:
288 for k, v in repoui.configitems(section):
289 for k, v in repoui.configitems(section):
289 baseui.setconfig(section, k, v)
290 baseui.setconfig(section, k, v)
General Comments 0
You need to be logged in to leave comments. Login now