##// END OF EJS Templates
gearbox: replace paster with something TurboGears2-ish that still works with the Pylons stack...
Mads Kiilerich -
r6509:2c3d3009 default
parent child Browse files
Show More
@@ -1,601 +1,610 b''
1 ################################################################################
1 ################################################################################
2 ################################################################################
2 ################################################################################
3 # Kallithea - Development config: #
3 # Kallithea - Development config: #
4 # listening on *:5000 #
4 # listening on *:5000 #
5 # sqlite and kallithea.db #
5 # sqlite and kallithea.db #
6 # initial_repo_scan = true #
6 # initial_repo_scan = true #
7 # set debug = true #
7 # set debug = true #
8 # verbose and colorful logging #
8 # verbose and colorful logging #
9 # #
9 # #
10 # The %(here)s variable will be replaced with the parent directory of this file#
10 # The %(here)s variable will be replaced with the parent directory of this file#
11 ################################################################################
11 ################################################################################
12 ################################################################################
12 ################################################################################
13
13
14 [DEFAULT]
14 [DEFAULT]
15 debug = true
15 debug = true
16 pdebug = false
16 pdebug = false
17
17
18 ################################################################################
18 ################################################################################
19 ## Email settings ##
19 ## Email settings ##
20 ## ##
20 ## ##
21 ## Refer to the documentation ("Email settings") for more details. ##
21 ## Refer to the documentation ("Email settings") for more details. ##
22 ## ##
22 ## ##
23 ## It is recommended to use a valid sender address that passes access ##
23 ## It is recommended to use a valid sender address that passes access ##
24 ## validation and spam filtering in mail servers. ##
24 ## validation and spam filtering in mail servers. ##
25 ################################################################################
25 ################################################################################
26
26
27 ## 'From' header for application emails. You can optionally add a name.
27 ## 'From' header for application emails. You can optionally add a name.
28 ## Default:
28 ## Default:
29 #app_email_from = Kallithea
29 #app_email_from = Kallithea
30 ## Examples:
30 ## Examples:
31 #app_email_from = Kallithea <kallithea-noreply@example.com>
31 #app_email_from = Kallithea <kallithea-noreply@example.com>
32 #app_email_from = kallithea-noreply@example.com
32 #app_email_from = kallithea-noreply@example.com
33
33
34 ## Subject prefix for application emails.
34 ## Subject prefix for application emails.
35 ## A space between this prefix and the real subject is automatically added.
35 ## A space between this prefix and the real subject is automatically added.
36 ## Default:
36 ## Default:
37 #email_prefix =
37 #email_prefix =
38 ## Example:
38 ## Example:
39 #email_prefix = [Kallithea]
39 #email_prefix = [Kallithea]
40
40
41 ## Recipients for error emails and fallback recipients of application mails.
41 ## Recipients for error emails and fallback recipients of application mails.
42 ## Multiple addresses can be specified, space-separated.
42 ## Multiple addresses can be specified, space-separated.
43 ## Only addresses are allowed, do not add any name part.
43 ## Only addresses are allowed, do not add any name part.
44 ## Default:
44 ## Default:
45 #email_to =
45 #email_to =
46 ## Examples:
46 ## Examples:
47 #email_to = admin@example.com
47 #email_to = admin@example.com
48 #email_to = admin@example.com another_admin@example.com
48 #email_to = admin@example.com another_admin@example.com
49
49
50 ## 'From' header for error emails. You can optionally add a name.
50 ## 'From' header for error emails. You can optionally add a name.
51 ## Default:
51 ## Default:
52 #error_email_from = pylons@yourapp.com
52 #error_email_from = pylons@yourapp.com
53 ## Examples:
53 ## Examples:
54 #error_email_from = Kallithea Errors <kallithea-noreply@example.com>
54 #error_email_from = Kallithea Errors <kallithea-noreply@example.com>
55 #error_email_from = paste_error@example.com
55 #error_email_from = paste_error@example.com
56
56
57 ## SMTP server settings
57 ## SMTP server settings
58 ## If specifying credentials, make sure to use secure connections.
58 ## If specifying credentials, make sure to use secure connections.
59 ## Default: Send unencrypted unauthenticated mails to the specified smtp_server.
59 ## Default: Send unencrypted unauthenticated mails to the specified smtp_server.
60 ## For "SSL", use smtp_use_ssl = true and smtp_port = 465.
60 ## For "SSL", use smtp_use_ssl = true and smtp_port = 465.
61 ## For "STARTTLS", use smtp_use_tls = true and smtp_port = 587.
61 ## For "STARTTLS", use smtp_use_tls = true and smtp_port = 587.
62 #smtp_server = smtp.example.com
62 #smtp_server = smtp.example.com
63 #smtp_username =
63 #smtp_username =
64 #smtp_password =
64 #smtp_password =
65 #smtp_port = 25
65 #smtp_port = 25
66 #smtp_use_ssl = false
66 #smtp_use_ssl = false
67 #smtp_use_tls = false
67 #smtp_use_tls = false
68
68
69 [server:main]
69 [server:main]
70 ## PASTE ##
70 ## Gearbox default web server ##
71 #use = egg:Paste#http
71 #use = egg:gearbox#wsgiref
72 ## nr of worker threads to spawn
72 ## nr of worker threads to spawn
73 #threadpool_workers = 1
73 #threadpool_workers = 1
74 ## max request before thread respawn
74 ## max request before thread respawn
75 #threadpool_max_requests = 100
75 #threadpool_max_requests = 100
76 ## option to use threads of process
76 ## option to use threads of process
77 #use_threadpool = true
77 #use_threadpool = true
78
78
79 ## Gearbox gevent web server ##
80 #use = egg:gearbox#gevent
81
79 ## WAITRESS ##
82 ## WAITRESS ##
80 use = egg:waitress#main
83 use = egg:waitress#main
81 ## number of worker threads
84 ## number of worker threads
82 threads = 1
85 threads = 1
83 ## MAX BODY SIZE 100GB
86 ## MAX BODY SIZE 100GB
84 max_request_body_size = 107374182400
87 max_request_body_size = 107374182400
85 ## use poll instead of select, fixes fd limits, may not work on old
88 ## use poll instead of select, fixes fd limits, may not work on old
86 ## windows systems.
89 ## windows systems.
87 #asyncore_use_poll = True
90 #asyncore_use_poll = True
88
91
89 ## GUNICORN ##
92 ## GUNICORN ##
90 #use = egg:gunicorn#main
93 #use = egg:gunicorn#main
91 ## number of process workers. You must set `instance_id = *` when this option
94 ## number of process workers. You must set `instance_id = *` when this option
92 ## is set to more than one worker
95 ## is set to more than one worker
93 #workers = 1
96 #workers = 1
94 ## process name
97 ## process name
95 #proc_name = kallithea
98 #proc_name = kallithea
96 ## type of worker class, one of sync, eventlet, gevent, tornado
99 ## type of worker class, one of sync, eventlet, gevent, tornado
97 ## recommended for bigger setup is using of of other than sync one
100 ## recommended for bigger setup is using of of other than sync one
98 #worker_class = sync
101 #worker_class = sync
99 #max_requests = 1000
102 #max_requests = 1000
100 ## amount of time a worker can handle request before it gets killed and
103 ## amount of time a worker can handle request before it gets killed and
101 ## restarted
104 ## restarted
102 #timeout = 3600
105 #timeout = 3600
103
106
104 ## UWSGI ##
107 ## UWSGI ##
105 ## run with uwsgi --ini-paste-logged <inifile.ini>
108 ## run with uwsgi --ini-paste-logged <inifile.ini>
106 #[uwsgi]
109 #[uwsgi]
107 #socket = /tmp/uwsgi.sock
110 #socket = /tmp/uwsgi.sock
108 #master = true
111 #master = true
109 #http = 127.0.0.1:5000
112 #http = 127.0.0.1:5000
110
113
111 ## set as deamon and redirect all output to file
114 ## set as deamon and redirect all output to file
112 #daemonize = ./uwsgi_kallithea.log
115 #daemonize = ./uwsgi_kallithea.log
113
116
114 ## master process PID
117 ## master process PID
115 #pidfile = ./uwsgi_kallithea.pid
118 #pidfile = ./uwsgi_kallithea.pid
116
119
117 ## stats server with workers statistics, use uwsgitop
120 ## stats server with workers statistics, use uwsgitop
118 ## for monitoring, `uwsgitop 127.0.0.1:1717`
121 ## for monitoring, `uwsgitop 127.0.0.1:1717`
119 #stats = 127.0.0.1:1717
122 #stats = 127.0.0.1:1717
120 #memory-report = true
123 #memory-report = true
121
124
122 ## log 5XX errors
125 ## log 5XX errors
123 #log-5xx = true
126 #log-5xx = true
124
127
125 ## Set the socket listen queue size.
128 ## Set the socket listen queue size.
126 #listen = 256
129 #listen = 256
127
130
128 ## Gracefully Reload workers after the specified amount of managed requests
131 ## Gracefully Reload workers after the specified amount of managed requests
129 ## (avoid memory leaks).
132 ## (avoid memory leaks).
130 #max-requests = 1000
133 #max-requests = 1000
131
134
132 ## enable large buffers
135 ## enable large buffers
133 #buffer-size = 65535
136 #buffer-size = 65535
134
137
135 ## socket and http timeouts ##
138 ## socket and http timeouts ##
136 #http-timeout = 3600
139 #http-timeout = 3600
137 #socket-timeout = 3600
140 #socket-timeout = 3600
138
141
139 ## Log requests slower than the specified number of milliseconds.
142 ## Log requests slower than the specified number of milliseconds.
140 #log-slow = 10
143 #log-slow = 10
141
144
142 ## Exit if no app can be loaded.
145 ## Exit if no app can be loaded.
143 #need-app = true
146 #need-app = true
144
147
145 ## Set lazy mode (load apps in workers instead of master).
148 ## Set lazy mode (load apps in workers instead of master).
146 #lazy = true
149 #lazy = true
147
150
148 ## scaling ##
151 ## scaling ##
149 ## set cheaper algorithm to use, if not set default will be used
152 ## set cheaper algorithm to use, if not set default will be used
150 #cheaper-algo = spare
153 #cheaper-algo = spare
151
154
152 ## minimum number of workers to keep at all times
155 ## minimum number of workers to keep at all times
153 #cheaper = 1
156 #cheaper = 1
154
157
155 ## number of workers to spawn at startup
158 ## number of workers to spawn at startup
156 #cheaper-initial = 1
159 #cheaper-initial = 1
157
160
158 ## maximum number of workers that can be spawned
161 ## maximum number of workers that can be spawned
159 #workers = 4
162 #workers = 4
160
163
161 ## how many workers should be spawned at a time
164 ## how many workers should be spawned at a time
162 #cheaper-step = 1
165 #cheaper-step = 1
163
166
164 ## COMMON ##
167 ## COMMON ##
165 #host = 127.0.0.1
168 #host = 127.0.0.1
166 host = 0.0.0.0
169 host = 0.0.0.0
167 port = 5000
170 port = 5000
168
171
169 ## middleware for hosting the WSGI application under a URL prefix
172 ## middleware for hosting the WSGI application under a URL prefix
170 #[filter:proxy-prefix]
173 #[filter:proxy-prefix]
171 #use = egg:PasteDeploy#prefix
174 #use = egg:PasteDeploy#prefix
172 #prefix = /<your-prefix>
175 #prefix = /<your-prefix>
173
176
174 [app:main]
177 [app:main]
175 use = egg:kallithea
178 use = egg:kallithea
176 ## enable proxy prefix middleware
179 ## enable proxy prefix middleware
177 #filter-with = proxy-prefix
180 #filter-with = proxy-prefix
178
181
179 full_stack = true
182 full_stack = true
180 static_files = true
183 static_files = true
181 ## Available Languages:
184 ## Available Languages:
182 ## cs de fr hu ja nl_BE pl pt_BR ru sk zh_CN zh_TW
185 ## cs de fr hu ja nl_BE pl pt_BR ru sk zh_CN zh_TW
183 lang =
186 lang =
184 cache_dir = %(here)s/data
187 cache_dir = %(here)s/data
185 index_dir = %(here)s/data/index
188 index_dir = %(here)s/data/index
186
189
187 ## perform a full repository scan on each server start, this should be
190 ## perform a full repository scan on each server start, this should be
188 ## set to false after first startup, to allow faster server restarts.
191 ## set to false after first startup, to allow faster server restarts.
189 #initial_repo_scan = false
192 #initial_repo_scan = false
190 initial_repo_scan = true
193 initial_repo_scan = true
191
194
192 ## uncomment and set this path to use archive download cache
195 ## uncomment and set this path to use archive download cache
193 archive_cache_dir = %(here)s/tarballcache
196 archive_cache_dir = %(here)s/tarballcache
194
197
195 ## change this to unique ID for security
198 ## change this to unique ID for security
196 app_instance_uuid = development-not-secret
199 app_instance_uuid = development-not-secret
197
200
198 ## cut off limit for large diffs (size in bytes)
201 ## cut off limit for large diffs (size in bytes)
199 cut_off_limit = 256000
202 cut_off_limit = 256000
200
203
201 ## force https in Kallithea, fixes https redirects, assumes it's always https
204 ## force https in Kallithea, fixes https redirects, assumes it's always https
202 force_https = false
205 force_https = false
203
206
204 ## use Strict-Transport-Security headers
207 ## use Strict-Transport-Security headers
205 use_htsts = false
208 use_htsts = false
206
209
207 ## number of commits stats will parse on each iteration
210 ## number of commits stats will parse on each iteration
208 commit_parse_limit = 25
211 commit_parse_limit = 25
209
212
210 ## path to git executable
213 ## path to git executable
211 git_path = git
214 git_path = git
212
215
213 ## git rev filter option, --all is the default filter, if you need to
216 ## git rev filter option, --all is the default filter, if you need to
214 ## hide all refs in changelog switch this to --branches --tags
217 ## hide all refs in changelog switch this to --branches --tags
215 #git_rev_filter = --branches --tags
218 #git_rev_filter = --branches --tags
216
219
217 ## RSS feed options
220 ## RSS feed options
218 rss_cut_off_limit = 256000
221 rss_cut_off_limit = 256000
219 rss_items_per_page = 10
222 rss_items_per_page = 10
220 rss_include_diff = false
223 rss_include_diff = false
221
224
222 ## options for showing and identifying changesets
225 ## options for showing and identifying changesets
223 show_sha_length = 12
226 show_sha_length = 12
224 show_revision_number = false
227 show_revision_number = false
225
228
226 ## Canonical URL to use when creating full URLs in UI and texts.
229 ## Canonical URL to use when creating full URLs in UI and texts.
227 ## Useful when the site is available under different names or protocols.
230 ## Useful when the site is available under different names or protocols.
228 ## Defaults to what is provided in the WSGI environment.
231 ## Defaults to what is provided in the WSGI environment.
229 #canonical_url = https://kallithea.example.com/repos
232 #canonical_url = https://kallithea.example.com/repos
230
233
231 ## gist URL alias, used to create nicer urls for gist. This should be an
234 ## gist URL alias, used to create nicer urls for gist. This should be an
232 ## url that does rewrites to _admin/gists/<gistid>.
235 ## url that does rewrites to _admin/gists/<gistid>.
233 ## example: http://gist.example.com/{gistid}. Empty means use the internal
236 ## example: http://gist.example.com/{gistid}. Empty means use the internal
234 ## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid>
237 ## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid>
235 gist_alias_url =
238 gist_alias_url =
236
239
237 ## white list of API enabled controllers. This allows to add list of
240 ## white list of API enabled controllers. This allows to add list of
238 ## controllers to which access will be enabled by api_key. eg: to enable
241 ## controllers to which access will be enabled by api_key. eg: to enable
239 ## api access to raw_files put `FilesController:raw`, to enable access to patches
242 ## api access to raw_files put `FilesController:raw`, to enable access to patches
240 ## add `ChangesetController:changeset_patch`. This list should be "," separated
243 ## add `ChangesetController:changeset_patch`. This list should be "," separated
241 ## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
244 ## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
242 ## Recommended settings below are commented out:
245 ## Recommended settings below are commented out:
243 api_access_controllers_whitelist =
246 api_access_controllers_whitelist =
244 # ChangesetController:changeset_patch,
247 # ChangesetController:changeset_patch,
245 # ChangesetController:changeset_raw,
248 # ChangesetController:changeset_raw,
246 # FilesController:raw,
249 # FilesController:raw,
247 # FilesController:archivefile
250 # FilesController:archivefile
248
251
249 ## default encoding used to convert from and to unicode
252 ## default encoding used to convert from and to unicode
250 ## can be also a comma separated list of encoding in case of mixed encodings
253 ## can be also a comma separated list of encoding in case of mixed encodings
251 default_encoding = utf8
254 default_encoding = utf8
252
255
253 ## issue tracker for Kallithea (leave blank to disable, absent for default)
256 ## issue tracker for Kallithea (leave blank to disable, absent for default)
254 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
257 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
255
258
256 ## issue tracking mapping for commits messages
259 ## issue tracking mapping for commits messages
257 ## comment out issue_pat, issue_server, issue_prefix to enable
260 ## comment out issue_pat, issue_server, issue_prefix to enable
258
261
259 ## pattern to get the issues from commit messages
262 ## pattern to get the issues from commit messages
260 ## default one used here is #<numbers> with a regex passive group for `#`
263 ## default one used here is #<numbers> with a regex passive group for `#`
261 ## {id} will be all groups matched from this pattern
264 ## {id} will be all groups matched from this pattern
262
265
263 issue_pat = (?:\s*#)(\d+)
266 issue_pat = (?:\s*#)(\d+)
264
267
265 ## server url to the issue, each {id} will be replaced with match
268 ## server url to the issue, each {id} will be replaced with match
266 ## fetched from the regex and {repo} is replaced with full repository name
269 ## fetched from the regex and {repo} is replaced with full repository name
267 ## including groups {repo_name} is replaced with just name of repo
270 ## including groups {repo_name} is replaced with just name of repo
268
271
269 issue_server_link = https://issues.example.com/{repo}/issue/{id}
272 issue_server_link = https://issues.example.com/{repo}/issue/{id}
270
273
271 ## prefix to add to link to indicate it's an url
274 ## prefix to add to link to indicate it's an url
272 ## #314 will be replaced by <issue_prefix><id>
275 ## #314 will be replaced by <issue_prefix><id>
273
276
274 issue_prefix = #
277 issue_prefix = #
275
278
276 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
279 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
277 ## multiple patterns, to other issues server, wiki or others
280 ## multiple patterns, to other issues server, wiki or others
278 ## below an example how to create a wiki pattern
281 ## below an example how to create a wiki pattern
279 # wiki-some-id -> https://wiki.example.com/some-id
282 # wiki-some-id -> https://wiki.example.com/some-id
280
283
281 #issue_pat_wiki = (?:wiki-)(.+)
284 #issue_pat_wiki = (?:wiki-)(.+)
282 #issue_server_link_wiki = https://wiki.example.com/{id}
285 #issue_server_link_wiki = https://wiki.example.com/{id}
283 #issue_prefix_wiki = WIKI-
286 #issue_prefix_wiki = WIKI-
284
287
285 ## alternative return HTTP header for failed authentication. Default HTTP
288 ## alternative return HTTP header for failed authentication. Default HTTP
286 ## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
289 ## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
287 ## handling that. Set this variable to 403 to return HTTPForbidden
290 ## handling that. Set this variable to 403 to return HTTPForbidden
288 auth_ret_code =
291 auth_ret_code =
289
292
290 ## locking return code. When repository is locked return this HTTP code. 2XX
293 ## locking return code. When repository is locked return this HTTP code. 2XX
291 ## codes don't break the transactions while 4XX codes do
294 ## codes don't break the transactions while 4XX codes do
292 lock_ret_code = 423
295 lock_ret_code = 423
293
296
294 ## allows to change the repository location in settings page
297 ## allows to change the repository location in settings page
295 allow_repo_location_change = True
298 allow_repo_location_change = True
296
299
297 ## allows to setup custom hooks in settings page
300 ## allows to setup custom hooks in settings page
298 allow_custom_hooks_settings = True
301 allow_custom_hooks_settings = True
299
302
300 ## extra extensions for indexing, space separated and without the leading '.'.
303 ## extra extensions for indexing, space separated and without the leading '.'.
301 # index.extensions =
304 # index.extensions =
302 # gemfile
305 # gemfile
303 # lock
306 # lock
304
307
305 ## extra filenames for indexing, space separated
308 ## extra filenames for indexing, space separated
306 # index.filenames =
309 # index.filenames =
307 # .dockerignore
310 # .dockerignore
308 # .editorconfig
311 # .editorconfig
309 # INSTALL
312 # INSTALL
310 # CHANGELOG
313 # CHANGELOG
311
314
312 ####################################
315 ####################################
313 ### CELERY CONFIG ####
316 ### CELERY CONFIG ####
314 ####################################
317 ####################################
315
318
316 use_celery = false
319 use_celery = false
317
320
318 ## Example: connect to the virtual host 'rabbitmqhost' on localhost as rabbitmq:
321 ## Example: connect to the virtual host 'rabbitmqhost' on localhost as rabbitmq:
319 broker.url = amqp://rabbitmq:qewqew@localhost:5672/rabbitmqhost
322 broker.url = amqp://rabbitmq:qewqew@localhost:5672/rabbitmqhost
320
323
321 celery.imports = kallithea.lib.celerylib.tasks
324 celery.imports = kallithea.lib.celerylib.tasks
322 celery.accept.content = pickle
325 celery.accept.content = pickle
323 celery.result.backend = amqp
326 celery.result.backend = amqp
324 celery.result.dburi = amqp://
327 celery.result.dburi = amqp://
325 celery.result.serialier = json
328 celery.result.serialier = json
326
329
327 #celery.send.task.error.emails = true
330 #celery.send.task.error.emails = true
328 #celery.amqp.task.result.expires = 18000
331 #celery.amqp.task.result.expires = 18000
329
332
330 celeryd.concurrency = 2
333 celeryd.concurrency = 2
331 celeryd.max.tasks.per.child = 1
334 celeryd.max.tasks.per.child = 1
332
335
333 ## If true, tasks will never be sent to the queue, but executed locally instead.
336 ## If true, tasks will never be sent to the queue, but executed locally instead.
334 celery.always.eager = false
337 celery.always.eager = false
335
338
336 ####################################
339 ####################################
337 ### BEAKER CACHE ####
340 ### BEAKER CACHE ####
338 ####################################
341 ####################################
339
342
340 beaker.cache.data_dir = %(here)s/data/cache/data
343 beaker.cache.data_dir = %(here)s/data/cache/data
341 beaker.cache.lock_dir = %(here)s/data/cache/lock
344 beaker.cache.lock_dir = %(here)s/data/cache/lock
342
345
343 beaker.cache.regions = short_term,long_term,sql_cache_short
346 beaker.cache.regions = short_term,long_term,sql_cache_short
344
347
345 beaker.cache.short_term.type = memory
348 beaker.cache.short_term.type = memory
346 beaker.cache.short_term.expire = 60
349 beaker.cache.short_term.expire = 60
347 beaker.cache.short_term.key_length = 256
350 beaker.cache.short_term.key_length = 256
348
351
349 beaker.cache.long_term.type = memory
352 beaker.cache.long_term.type = memory
350 beaker.cache.long_term.expire = 36000
353 beaker.cache.long_term.expire = 36000
351 beaker.cache.long_term.key_length = 256
354 beaker.cache.long_term.key_length = 256
352
355
353 beaker.cache.sql_cache_short.type = memory
356 beaker.cache.sql_cache_short.type = memory
354 beaker.cache.sql_cache_short.expire = 10
357 beaker.cache.sql_cache_short.expire = 10
355 beaker.cache.sql_cache_short.key_length = 256
358 beaker.cache.sql_cache_short.key_length = 256
356
359
357 ####################################
360 ####################################
358 ### BEAKER SESSION ####
361 ### BEAKER SESSION ####
359 ####################################
362 ####################################
360
363
361 ## Name of session cookie. Should be unique for a given host and path, even when running
364 ## Name of session cookie. Should be unique for a given host and path, even when running
362 ## on different ports. Otherwise, cookie sessions will be shared and messed up.
365 ## on different ports. Otherwise, cookie sessions will be shared and messed up.
363 beaker.session.key = kallithea
366 beaker.session.key = kallithea
364 ## Sessions should always only be accessible by the browser, not directly by JavaScript.
367 ## Sessions should always only be accessible by the browser, not directly by JavaScript.
365 beaker.session.httponly = true
368 beaker.session.httponly = true
366 ## Session lifetime. 2592000 seconds is 30 days.
369 ## Session lifetime. 2592000 seconds is 30 days.
367 beaker.session.timeout = 2592000
370 beaker.session.timeout = 2592000
368
371
369 ## Server secret used with HMAC to ensure integrity of cookies.
372 ## Server secret used with HMAC to ensure integrity of cookies.
370 beaker.session.secret = development-not-secret
373 beaker.session.secret = development-not-secret
371 ## Further, encrypt the data with AES.
374 ## Further, encrypt the data with AES.
372 #beaker.session.encrypt_key = <key_for_encryption>
375 #beaker.session.encrypt_key = <key_for_encryption>
373 #beaker.session.validate_key = <validation_key>
376 #beaker.session.validate_key = <validation_key>
374
377
375 ## Type of storage used for the session, current types are
378 ## Type of storage used for the session, current types are
376 ## dbm, file, memcached, database, and memory.
379 ## dbm, file, memcached, database, and memory.
377
380
378 ## File system storage of session data. (default)
381 ## File system storage of session data. (default)
379 #beaker.session.type = file
382 #beaker.session.type = file
380
383
381 ## Cookie only, store all session data inside the cookie. Requires secure secrets.
384 ## Cookie only, store all session data inside the cookie. Requires secure secrets.
382 #beaker.session.type = cookie
385 #beaker.session.type = cookie
383
386
384 ## Database storage of session data.
387 ## Database storage of session data.
385 #beaker.session.type = ext:database
388 #beaker.session.type = ext:database
386 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/kallithea
389 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/kallithea
387 #beaker.session.table_name = db_session
390 #beaker.session.table_name = db_session
388
391
389 ############################
392 ############################
390 ## ERROR HANDLING SYSTEMS ##
393 ## ERROR HANDLING SYSTEMS ##
391 ############################
394 ############################
392
395
393 ####################
396 ####################
394 ### [appenlight] ###
397 ### [appenlight] ###
395 ####################
398 ####################
396
399
397 ## AppEnlight is tailored to work with Kallithea, see
400 ## AppEnlight is tailored to work with Kallithea, see
398 ## http://appenlight.com for details how to obtain an account
401 ## http://appenlight.com for details how to obtain an account
399 ## you must install python package `appenlight_client` to make it work
402 ## you must install python package `appenlight_client` to make it work
400
403
401 ## appenlight enabled
404 ## appenlight enabled
402 appenlight = false
405 appenlight = false
403
406
404 appenlight.server_url = https://api.appenlight.com
407 appenlight.server_url = https://api.appenlight.com
405 appenlight.api_key = YOUR_API_KEY
408 appenlight.api_key = YOUR_API_KEY
406
409
407 ## TWEAK AMOUNT OF INFO SENT HERE
410 ## TWEAK AMOUNT OF INFO SENT HERE
408
411
409 ## enables 404 error logging (default False)
412 ## enables 404 error logging (default False)
410 appenlight.report_404 = false
413 appenlight.report_404 = false
411
414
412 ## time in seconds after request is considered being slow (default 1)
415 ## time in seconds after request is considered being slow (default 1)
413 appenlight.slow_request_time = 1
416 appenlight.slow_request_time = 1
414
417
415 ## record slow requests in application
418 ## record slow requests in application
416 ## (needs to be enabled for slow datastore recording and time tracking)
419 ## (needs to be enabled for slow datastore recording and time tracking)
417 appenlight.slow_requests = true
420 appenlight.slow_requests = true
418
421
419 ## enable hooking to application loggers
422 ## enable hooking to application loggers
420 #appenlight.logging = true
423 #appenlight.logging = true
421
424
422 ## minimum log level for log capture
425 ## minimum log level for log capture
423 #appenlight.logging.level = WARNING
426 #appenlight.logging.level = WARNING
424
427
425 ## send logs only from erroneous/slow requests
428 ## send logs only from erroneous/slow requests
426 ## (saves API quota for intensive logging)
429 ## (saves API quota for intensive logging)
427 appenlight.logging_on_error = false
430 appenlight.logging_on_error = false
428
431
429 ## list of additional keywords that should be grabbed from environ object
432 ## list of additional keywords that should be grabbed from environ object
430 ## can be string with comma separated list of words in lowercase
433 ## can be string with comma separated list of words in lowercase
431 ## (by default client will always send following info:
434 ## (by default client will always send following info:
432 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
435 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
433 ## start with HTTP* this list be extended with additional keywords here
436 ## start with HTTP* this list be extended with additional keywords here
434 appenlight.environ_keys_whitelist =
437 appenlight.environ_keys_whitelist =
435
438
436 ## list of keywords that should be blanked from request object
439 ## list of keywords that should be blanked from request object
437 ## can be string with comma separated list of words in lowercase
440 ## can be string with comma separated list of words in lowercase
438 ## (by default client will always blank keys that contain following words
441 ## (by default client will always blank keys that contain following words
439 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
442 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
440 ## this list be extended with additional keywords set here
443 ## this list be extended with additional keywords set here
441 appenlight.request_keys_blacklist =
444 appenlight.request_keys_blacklist =
442
445
443 ## list of namespaces that should be ignores when gathering log entries
446 ## list of namespaces that should be ignores when gathering log entries
444 ## can be string with comma separated list of namespaces
447 ## can be string with comma separated list of namespaces
445 ## (by default the client ignores own entries: appenlight_client.client)
448 ## (by default the client ignores own entries: appenlight_client.client)
446 appenlight.log_namespace_blacklist =
449 appenlight.log_namespace_blacklist =
447
450
448 ################
451 ################
449 ### [sentry] ###
452 ### [sentry] ###
450 ################
453 ################
451
454
452 ## sentry is a alternative open source error aggregator
455 ## sentry is a alternative open source error aggregator
453 ## you must install python packages `sentry` and `raven` to enable
456 ## you must install python packages `sentry` and `raven` to enable
454
457
455 sentry.dsn = YOUR_DNS
458 sentry.dsn = YOUR_DNS
456 sentry.servers =
459 sentry.servers =
457 sentry.name =
460 sentry.name =
458 sentry.key =
461 sentry.key =
459 sentry.public_key =
462 sentry.public_key =
460 sentry.secret_key =
463 sentry.secret_key =
461 sentry.project =
464 sentry.project =
462 sentry.site =
465 sentry.site =
463 sentry.include_paths =
466 sentry.include_paths =
464 sentry.exclude_paths =
467 sentry.exclude_paths =
465
468
466 ################################################################################
469 ################################################################################
467 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
470 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
468 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
471 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
469 ## execute malicious code after an exception is raised. ##
472 ## execute malicious code after an exception is raised. ##
470 ################################################################################
473 ################################################################################
471 #set debug = false
474 #set debug = false
472 set debug = true
475 set debug = true
473
476
474 ##################################
477 ##################################
475 ### LOGVIEW CONFIG ###
478 ### LOGVIEW CONFIG ###
476 ##################################
479 ##################################
477
480
478 logview.sqlalchemy = #faa
481 logview.sqlalchemy = #faa
479 logview.pylons.templating = #bfb
482 logview.pylons.templating = #bfb
480 logview.pylons.util = #eee
483 logview.pylons.util = #eee
481
484
482 #########################################################
485 #########################################################
483 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
486 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
484 #########################################################
487 #########################################################
485
488
486 # SQLITE [default]
489 # SQLITE [default]
487 sqlalchemy.url = sqlite:///%(here)s/kallithea.db?timeout=60
490 sqlalchemy.url = sqlite:///%(here)s/kallithea.db?timeout=60
488
491
489 # POSTGRESQL
492 # POSTGRESQL
490 #sqlalchemy.url = postgresql://user:pass@localhost/kallithea
493 #sqlalchemy.url = postgresql://user:pass@localhost/kallithea
491
494
492 # MySQL
495 # MySQL
493 #sqlalchemy.url = mysql://user:pass@localhost/kallithea?charset=utf8
496 #sqlalchemy.url = mysql://user:pass@localhost/kallithea?charset=utf8
494
497
495 # see sqlalchemy docs for others
498 # see sqlalchemy docs for others
496
499
497 sqlalchemy.echo = false
500 sqlalchemy.echo = false
498 sqlalchemy.pool_recycle = 3600
501 sqlalchemy.pool_recycle = 3600
499
502
500 ################################
503 ################################
501 ### ALEMBIC CONFIGURATION ####
504 ### ALEMBIC CONFIGURATION ####
502 ################################
505 ################################
503
506
504 [alembic]
507 [alembic]
505 script_location = kallithea:alembic
508 script_location = kallithea:alembic
506
509
507 ################################
510 ################################
508 ### LOGGING CONFIGURATION ####
511 ### LOGGING CONFIGURATION ####
509 ################################
512 ################################
510
513
511 [loggers]
514 [loggers]
512 keys = root, routes, kallithea, sqlalchemy, beaker, templates, whoosh_indexer
515 keys = root, routes, kallithea, sqlalchemy, gearbox, beaker, templates, whoosh_indexer
513
516
514 [handlers]
517 [handlers]
515 keys = console, console_sql
518 keys = console, console_sql
516
519
517 [formatters]
520 [formatters]
518 keys = generic, color_formatter, color_formatter_sql
521 keys = generic, color_formatter, color_formatter_sql
519
522
520 #############
523 #############
521 ## LOGGERS ##
524 ## LOGGERS ##
522 #############
525 #############
523
526
524 [logger_root]
527 [logger_root]
525 level = NOTSET
528 level = NOTSET
526 handlers = console
529 handlers = console
527
530
528 [logger_routes]
531 [logger_routes]
529 level = DEBUG
532 level = DEBUG
530 handlers =
533 handlers =
531 qualname = routes.middleware
534 qualname = routes.middleware
532 ## "level = DEBUG" logs the route matched and routing variables.
535 ## "level = DEBUG" logs the route matched and routing variables.
533 propagate = 1
536 propagate = 1
534
537
535 [logger_beaker]
538 [logger_beaker]
536 level = DEBUG
539 level = DEBUG
537 handlers =
540 handlers =
538 qualname = beaker.container
541 qualname = beaker.container
539 propagate = 1
542 propagate = 1
540
543
541 [logger_templates]
544 [logger_templates]
542 level = INFO
545 level = INFO
543 handlers =
546 handlers =
544 qualname = pylons.templating
547 qualname = pylons.templating
545 propagate = 1
548 propagate = 1
546
549
547 [logger_kallithea]
550 [logger_kallithea]
548 level = DEBUG
551 level = DEBUG
549 handlers =
552 handlers =
550 qualname = kallithea
553 qualname = kallithea
551 propagate = 1
554 propagate = 1
552
555
556 [logger_gearbox]
557 level = DEBUG
558 handlers =
559 qualname = gearbox
560 propagate = 1
561
553 [logger_sqlalchemy]
562 [logger_sqlalchemy]
554 level = INFO
563 level = INFO
555 handlers = console_sql
564 handlers = console_sql
556 qualname = sqlalchemy.engine
565 qualname = sqlalchemy.engine
557 propagate = 0
566 propagate = 0
558
567
559 [logger_whoosh_indexer]
568 [logger_whoosh_indexer]
560 level = DEBUG
569 level = DEBUG
561 handlers =
570 handlers =
562 qualname = whoosh_indexer
571 qualname = whoosh_indexer
563 propagate = 1
572 propagate = 1
564
573
565 ##############
574 ##############
566 ## HANDLERS ##
575 ## HANDLERS ##
567 ##############
576 ##############
568
577
569 [handler_console]
578 [handler_console]
570 class = StreamHandler
579 class = StreamHandler
571 args = (sys.stderr,)
580 args = (sys.stderr,)
572 #level = INFO
581 #level = INFO
573 level = DEBUG
582 level = DEBUG
574 #formatter = generic
583 #formatter = generic
575 formatter = color_formatter
584 formatter = color_formatter
576
585
577 [handler_console_sql]
586 [handler_console_sql]
578 class = StreamHandler
587 class = StreamHandler
579 args = (sys.stderr,)
588 args = (sys.stderr,)
580 #level = WARN
589 #level = WARN
581 level = DEBUG
590 level = DEBUG
582 #formatter = generic
591 #formatter = generic
583 formatter = color_formatter_sql
592 formatter = color_formatter_sql
584
593
585 ################
594 ################
586 ## FORMATTERS ##
595 ## FORMATTERS ##
587 ################
596 ################
588
597
589 [formatter_generic]
598 [formatter_generic]
590 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
599 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
591 datefmt = %Y-%m-%d %H:%M:%S
600 datefmt = %Y-%m-%d %H:%M:%S
592
601
593 [formatter_color_formatter]
602 [formatter_color_formatter]
594 class = kallithea.lib.colored_formatter.ColorFormatter
603 class = kallithea.lib.colored_formatter.ColorFormatter
595 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
604 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
596 datefmt = %Y-%m-%d %H:%M:%S
605 datefmt = %Y-%m-%d %H:%M:%S
597
606
598 [formatter_color_formatter_sql]
607 [formatter_color_formatter_sql]
599 class = kallithea.lib.colored_formatter.ColorFormatterSql
608 class = kallithea.lib.colored_formatter.ColorFormatterSql
600 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
609 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
601 datefmt = %Y-%m-%d %H:%M:%S
610 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,227 +1,227 b''
1 .. _contributing:
1 .. _contributing:
2
2
3 =========================
3 =========================
4 Contributing to Kallithea
4 Contributing to Kallithea
5 =========================
5 =========================
6
6
7 Kallithea is developed and maintained by its users. Please join us and scratch
7 Kallithea is developed and maintained by its users. Please join us and scratch
8 your own itch.
8 your own itch.
9
9
10
10
11 Infrastructure
11 Infrastructure
12 --------------
12 --------------
13
13
14 The main repository is hosted on Our Own Kallithea (aka OOK) at
14 The main repository is hosted on Our Own Kallithea (aka OOK) at
15 https://kallithea-scm.org/repos/kallithea/, our self-hosted instance
15 https://kallithea-scm.org/repos/kallithea/, our self-hosted instance
16 of Kallithea.
16 of Kallithea.
17
17
18 For now, we use Bitbucket_ for `pull requests`_ and `issue tracking`_. The
18 For now, we use Bitbucket_ for `pull requests`_ and `issue tracking`_. The
19 issue tracker is for tracking bugs, not for support, discussion, or ideas --
19 issue tracker is for tracking bugs, not for support, discussion, or ideas --
20 please use the `mailing list`_ or :ref:`IRC <readme>` to reach the community.
20 please use the `mailing list`_ or :ref:`IRC <readme>` to reach the community.
21
21
22 We use Weblate_ to translate the user interface messages into languages other
22 We use Weblate_ to translate the user interface messages into languages other
23 than English. Join our project on `Hosted Weblate`_ to help us.
23 than English. Join our project on `Hosted Weblate`_ to help us.
24 To register, you can use your Bitbucket or GitHub account. See :ref:`translations`
24 To register, you can use your Bitbucket or GitHub account. See :ref:`translations`
25 for more details.
25 for more details.
26
26
27
27
28 Getting started
28 Getting started
29 ---------------
29 ---------------
30
30
31 To get started with development::
31 To get started with development::
32
32
33 hg clone https://kallithea-scm.org/repos/kallithea
33 hg clone https://kallithea-scm.org/repos/kallithea
34 cd kallithea
34 cd kallithea
35 virtualenv ../kallithea-venv
35 virtualenv ../kallithea-venv
36 source ../kallithea-venv/bin/activate
36 source ../kallithea-venv/bin/activate
37 pip install --upgrade pip setuptools
37 pip install --upgrade pip setuptools
38 pip install -e .
38 pip install -e .
39 paster make-config Kallithea my.ini
39 TODO make-config Kallithea my.ini
40 paster setup-db my.ini --user=user --email=user@example.com --password=password --repos=/tmp
40 gearbox setup-db -c my.ini --user=user --email=user@example.com --password=password --repos=/tmp
41 paster serve my.ini --reload &
41 gearbox serve -c my.ini --reload &
42 firefox http://127.0.0.1:5000/
42 firefox http://127.0.0.1:5000/
43
43
44 You can also start out by forking https://bitbucket.org/conservancy/kallithea
44 You can also start out by forking https://bitbucket.org/conservancy/kallithea
45 on Bitbucket_ and create a local clone of your own fork.
45 on Bitbucket_ and create a local clone of your own fork.
46
46
47
47
48 Running tests
48 Running tests
49 -------------
49 -------------
50
50
51 After finishing your changes make sure all tests pass cleanly. Install the test
51 After finishing your changes make sure all tests pass cleanly. Install the test
52 dependencies, then run the testsuite by invoking ``py.test`` from the
52 dependencies, then run the testsuite by invoking ``py.test`` from the
53 project root::
53 project root::
54
54
55 pip install -r dev_requirements.txt
55 pip install -r dev_requirements.txt
56 py.test
56 py.test
57
57
58 Note that testing on Python 2.6 also requires ``unittest2``.
58 Note that testing on Python 2.6 also requires ``unittest2``.
59
59
60 You can also use ``tox`` to run the tests with all supported Python versions
60 You can also use ``tox`` to run the tests with all supported Python versions
61 (currently Python 2.6--2.7).
61 (currently Python 2.6--2.7).
62
62
63 When running tests, Kallithea uses `kallithea/tests/test.ini` and populates the
63 When running tests, Kallithea uses `kallithea/tests/test.ini` and populates the
64 SQLite database specified there.
64 SQLite database specified there.
65
65
66 It is possible to avoid recreating the full test database on each invocation of
66 It is possible to avoid recreating the full test database on each invocation of
67 the tests, thus eliminating the initial delay. To achieve this, run the tests as::
67 the tests, thus eliminating the initial delay. To achieve this, run the tests as::
68
68
69 paster serve kallithea/tests/test.ini --pid-file=test.pid --daemon
69 gearbox serve -c kallithea/tests/test.ini --pid-file=test.pid --daemon
70 KALLITHEA_WHOOSH_TEST_DISABLE=1 KALLITHEA_NO_TMP_PATH=1 py.test
70 KALLITHEA_WHOOSH_TEST_DISABLE=1 KALLITHEA_NO_TMP_PATH=1 py.test
71 kill -9 $(cat test.pid)
71 kill -9 $(cat test.pid)
72
72
73 In these commands, the following variables are used::
73 In these commands, the following variables are used::
74
74
75 KALLITHEA_WHOOSH_TEST_DISABLE=1 - skip whoosh index building and tests
75 KALLITHEA_WHOOSH_TEST_DISABLE=1 - skip whoosh index building and tests
76 KALLITHEA_NO_TMP_PATH=1 - disable new temp path for tests, used mostly for testing_vcs_operations
76 KALLITHEA_NO_TMP_PATH=1 - disable new temp path for tests, used mostly for testing_vcs_operations
77
77
78 You can run individual tests by specifying their path as argument to py.test.
78 You can run individual tests by specifying their path as argument to py.test.
79 py.test also has many more options, see `py.test -h`. Some useful options
79 py.test also has many more options, see `py.test -h`. Some useful options
80 are::
80 are::
81
81
82 -k EXPRESSION only run tests which match the given substring
82 -k EXPRESSION only run tests which match the given substring
83 expression. An expression is a python evaluable
83 expression. An expression is a python evaluable
84 expression where all names are substring-matched
84 expression where all names are substring-matched
85 against test names and their parent classes. Example:
85 against test names and their parent classes. Example:
86 -x, --exitfirst exit instantly on first error or failed test.
86 -x, --exitfirst exit instantly on first error or failed test.
87 --lf rerun only the tests that failed at the last run (or
87 --lf rerun only the tests that failed at the last run (or
88 all if none failed)
88 all if none failed)
89 --ff run all tests but run the last failures first. This
89 --ff run all tests but run the last failures first. This
90 may re-order tests and thus lead to repeated fixture
90 may re-order tests and thus lead to repeated fixture
91 setup/teardown
91 setup/teardown
92 --pdb start the interactive Python debugger on errors.
92 --pdb start the interactive Python debugger on errors.
93 -s, --capture=no don't capture stdout (any stdout output will be
93 -s, --capture=no don't capture stdout (any stdout output will be
94 printed immediately)
94 printed immediately)
95
95
96
96
97 Contribution guidelines
97 Contribution guidelines
98 -----------------------
98 -----------------------
99
99
100 Kallithea is GPLv3 and we assume all contributions are made by the
100 Kallithea is GPLv3 and we assume all contributions are made by the
101 committer/contributor and under GPLv3 unless explicitly stated. We do care a
101 committer/contributor and under GPLv3 unless explicitly stated. We do care a
102 lot about preservation of copyright and license information for existing code
102 lot about preservation of copyright and license information for existing code
103 that is brought into the project.
103 that is brought into the project.
104
104
105 Contributions will be accepted in most formats -- such as pull requests on
105 Contributions will be accepted in most formats -- such as pull requests on
106 Bitbucket, something hosted on your own Kallithea instance, or patches sent by
106 Bitbucket, something hosted on your own Kallithea instance, or patches sent by
107 email to the `kallithea-general`_ mailing list.
107 email to the `kallithea-general`_ mailing list.
108
108
109 When contributing via Bitbucket, please make your fork of
109 When contributing via Bitbucket, please make your fork of
110 https://bitbucket.org/conservancy/kallithea/ `non-publishing`_ -- it is one of
110 https://bitbucket.org/conservancy/kallithea/ `non-publishing`_ -- it is one of
111 the settings on "Repository details" page. This ensures your commits are in
111 the settings on "Repository details" page. This ensures your commits are in
112 "draft" phase and makes it easier for you to address feedback and for project
112 "draft" phase and makes it easier for you to address feedback and for project
113 maintainers to integrate your changes.
113 maintainers to integrate your changes.
114
114
115 .. _non-publishing: https://www.mercurial-scm.org/wiki/Phases#Publishing_Repository
115 .. _non-publishing: https://www.mercurial-scm.org/wiki/Phases#Publishing_Repository
116
116
117 Make sure to test your changes both manually and with the automatic tests
117 Make sure to test your changes both manually and with the automatic tests
118 before posting.
118 before posting.
119
119
120 We care about quality and review and keeping a clean repository history. We
120 We care about quality and review and keeping a clean repository history. We
121 might give feedback that requests polishing contributions until they are
121 might give feedback that requests polishing contributions until they are
122 "perfect". We might also rebase and collapse and make minor adjustments to your
122 "perfect". We might also rebase and collapse and make minor adjustments to your
123 changes when we apply them.
123 changes when we apply them.
124
124
125 We try to make sure we have consensus on the direction the project is taking.
125 We try to make sure we have consensus on the direction the project is taking.
126 Everything non-sensitive should be discussed in public -- preferably on the
126 Everything non-sensitive should be discussed in public -- preferably on the
127 mailing list. We aim at having all non-trivial changes reviewed by at least
127 mailing list. We aim at having all non-trivial changes reviewed by at least
128 one other core developer before pushing. Obvious non-controversial changes will
128 one other core developer before pushing. Obvious non-controversial changes will
129 be handled more casually.
129 be handled more casually.
130
130
131 For now we just have one official branch ("default") and will keep it so stable
131 For now we just have one official branch ("default") and will keep it so stable
132 that it can be (and is) used in production. Experimental changes should live
132 that it can be (and is) used in production. Experimental changes should live
133 elsewhere (for example in a pull request) until they are ready.
133 elsewhere (for example in a pull request) until they are ready.
134
134
135
135
136 Coding guidelines
136 Coding guidelines
137 -----------------
137 -----------------
138
138
139 We don't have a formal coding/formatting standard. We are currently using a mix
139 We don't have a formal coding/formatting standard. We are currently using a mix
140 of Mercurial's (https://www.mercurial-scm.org/wiki/CodingStyle), pep8, and
140 of Mercurial's (https://www.mercurial-scm.org/wiki/CodingStyle), pep8, and
141 consistency with existing code. Run ``scripts/run-all-cleanup`` before
141 consistency with existing code. Run ``scripts/run-all-cleanup`` before
142 committing to ensure some basic code formatting consistency.
142 committing to ensure some basic code formatting consistency.
143
143
144 We support both Python 2.6.x and 2.7.x and nothing else. For now we don't care
144 We support both Python 2.6.x and 2.7.x and nothing else. For now we don't care
145 about Python 3 compatibility.
145 about Python 3 compatibility.
146
146
147 We try to support the most common modern web browsers. IE9 is still supported
147 We try to support the most common modern web browsers. IE9 is still supported
148 to the extent it is feasible, IE8 is not.
148 to the extent it is feasible, IE8 is not.
149
149
150 We primarily support Linux and OS X on the server side but Windows should also work.
150 We primarily support Linux and OS X on the server side but Windows should also work.
151
151
152 HTML templates should use 2 spaces for indentation ... but be pragmatic. We
152 HTML templates should use 2 spaces for indentation ... but be pragmatic. We
153 should use templates cleverly and avoid duplication. We should use reasonable
153 should use templates cleverly and avoid duplication. We should use reasonable
154 semantic markup with element classes and IDs that can be used for styling and testing.
154 semantic markup with element classes and IDs that can be used for styling and testing.
155 We should only use inline styles in places where it really is semantic (such as
155 We should only use inline styles in places where it really is semantic (such as
156 ``display: none``).
156 ``display: none``).
157
157
158 JavaScript must use ``;`` between/after statements. Indentation 4 spaces. Inline
158 JavaScript must use ``;`` between/after statements. Indentation 4 spaces. Inline
159 multiline functions should be indented two levels -- one for the ``()`` and one for
159 multiline functions should be indented two levels -- one for the ``()`` and one for
160 ``{}``.
160 ``{}``.
161 Variables holding jQuery objects should be named with a leading ``$``.
161 Variables holding jQuery objects should be named with a leading ``$``.
162
162
163 Commit messages should have a leading short line summarizing the changes. For
163 Commit messages should have a leading short line summarizing the changes. For
164 bug fixes, put ``(Issue #123)`` at the end of this line.
164 bug fixes, put ``(Issue #123)`` at the end of this line.
165
165
166 Use American English grammar and spelling overall. Use `English title case`_ for
166 Use American English grammar and spelling overall. Use `English title case`_ for
167 page titles, button labels, headers, and 'labels' for fields in forms.
167 page titles, button labels, headers, and 'labels' for fields in forms.
168
168
169 .. _English title case: https://en.wikipedia.org/wiki/Capitalization#Title_case
169 .. _English title case: https://en.wikipedia.org/wiki/Capitalization#Title_case
170
170
171 Template helpers (that is, everything in ``kallithea.lib.helpers``)
171 Template helpers (that is, everything in ``kallithea.lib.helpers``)
172 should only be referenced from templates. If you need to call a
172 should only be referenced from templates. If you need to call a
173 helper from the Python code, consider moving the function somewhere
173 helper from the Python code, consider moving the function somewhere
174 else (e.g. to the model).
174 else (e.g. to the model).
175
175
176 Notes on the SQLAlchemy session
176 Notes on the SQLAlchemy session
177 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
177 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
178
178
179 Each HTTP request runs inside an independent SQLAlchemy session (as well
179 Each HTTP request runs inside an independent SQLAlchemy session (as well
180 as in an independent database transaction). Database model objects
180 as in an independent database transaction). Database model objects
181 (almost) always belong to a particular SQLAlchemy session, which means
181 (almost) always belong to a particular SQLAlchemy session, which means
182 that SQLAlchemy will ensure that they're kept in sync with the database
182 that SQLAlchemy will ensure that they're kept in sync with the database
183 (but also means that they cannot be shared across requests).
183 (but also means that they cannot be shared across requests).
184
184
185 Objects can be added to the session using ``Session().add``, but this is
185 Objects can be added to the session using ``Session().add``, but this is
186 rarely needed:
186 rarely needed:
187
187
188 * When creating a database object by calling the constructor directly,
188 * When creating a database object by calling the constructor directly,
189 it must explicitly be added to the session.
189 it must explicitly be added to the session.
190
190
191 * When creating an object using a factory function (like
191 * When creating an object using a factory function (like
192 ``create_repo``), the returned object has already (by convention)
192 ``create_repo``), the returned object has already (by convention)
193 been added to the session, and should not be added again.
193 been added to the session, and should not be added again.
194
194
195 * When getting an object from the session (via ``Session().query`` or
195 * When getting an object from the session (via ``Session().query`` or
196 any of the utility functions that look up objects in the database),
196 any of the utility functions that look up objects in the database),
197 it's already part of the session, and should not be added again.
197 it's already part of the session, and should not be added again.
198 SQLAlchemy monitors attribute modifications automatically for all
198 SQLAlchemy monitors attribute modifications automatically for all
199 objects it knows about and syncs them to the database.
199 objects it knows about and syncs them to the database.
200
200
201 SQLAlchemy also flushes changes to the database automatically; manually
201 SQLAlchemy also flushes changes to the database automatically; manually
202 calling ``Session().flush`` is usually only necessary when the Python
202 calling ``Session().flush`` is usually only necessary when the Python
203 code needs the database to assign an "auto-increment" primary key ID to
203 code needs the database to assign an "auto-increment" primary key ID to
204 a freshly created model object (before flushing, the ID attribute will
204 a freshly created model object (before flushing, the ID attribute will
205 be ``None``).
205 be ``None``).
206
206
207
207
208 "Roadmap"
208 "Roadmap"
209 ---------
209 ---------
210
210
211 We do not have a road map but are waiting for your contributions. Refer to the
211 We do not have a road map but are waiting for your contributions. Refer to the
212 wiki_ for some ideas of places we might want to go -- contributions in these
212 wiki_ for some ideas of places we might want to go -- contributions in these
213 areas are very welcome.
213 areas are very welcome.
214
214
215
215
216 Thank you for your contribution!
216 Thank you for your contribution!
217 --------------------------------
217 --------------------------------
218
218
219
219
220 .. _Weblate: http://weblate.org/
220 .. _Weblate: http://weblate.org/
221 .. _issue tracking: https://bitbucket.org/conservancy/kallithea/issues?status=new&status=open
221 .. _issue tracking: https://bitbucket.org/conservancy/kallithea/issues?status=new&status=open
222 .. _pull requests: https://bitbucket.org/conservancy/kallithea/pull-requests
222 .. _pull requests: https://bitbucket.org/conservancy/kallithea/pull-requests
223 .. _bitbucket: http://bitbucket.org/
223 .. _bitbucket: http://bitbucket.org/
224 .. _mailing list: http://lists.sfconservancy.org/mailman/listinfo/kallithea-general
224 .. _mailing list: http://lists.sfconservancy.org/mailman/listinfo/kallithea-general
225 .. _kallithea-general: http://lists.sfconservancy.org/mailman/listinfo/kallithea-general
225 .. _kallithea-general: http://lists.sfconservancy.org/mailman/listinfo/kallithea-general
226 .. _Hosted Weblate: https://hosted.weblate.org/projects/kallithea/kallithea/
226 .. _Hosted Weblate: https://hosted.weblate.org/projects/kallithea/kallithea/
227 .. _wiki: https://bitbucket.org/conservancy/kallithea/wiki/Home
227 .. _wiki: https://bitbucket.org/conservancy/kallithea/wiki/Home
@@ -1,74 +1,74 b''
1 =======================
1 =======================
2 Database schema changes
2 Database schema changes
3 =======================
3 =======================
4
4
5 Kallithea uses Alembic for :ref:`database migrations <upgrade_db>`
5 Kallithea uses Alembic for :ref:`database migrations <upgrade_db>`
6 (upgrades and downgrades).
6 (upgrades and downgrades).
7
7
8 If you are developing a Kallithea feature that requires database schema
8 If you are developing a Kallithea feature that requires database schema
9 changes, you should make a matching Alembic database migration script:
9 changes, you should make a matching Alembic database migration script:
10
10
11 1. :ref:`Create a Kallithea configuration and database <setup>` for testing
11 1. :ref:`Create a Kallithea configuration and database <setup>` for testing
12 the migration script, or use existing ``development.ini`` setup.
12 the migration script, or use existing ``development.ini`` setup.
13
13
14 Ensure that this database is up to date with the latest database
14 Ensure that this database is up to date with the latest database
15 schema *before* the changes you're currently developing. (Do not
15 schema *before* the changes you're currently developing. (Do not
16 create the database while your new schema changes are applied.)
16 create the database while your new schema changes are applied.)
17
17
18 2. Create a separate throwaway configuration for iterating on the actual
18 2. Create a separate throwaway configuration for iterating on the actual
19 database changes::
19 database changes::
20
20
21 paster make-config Kallithea temp.ini
21 TODO make-config Kallithea temp.ini
22
22
23 Edit the file to change database settings. SQLite is typically fine,
23 Edit the file to change database settings. SQLite is typically fine,
24 but make sure to change the path to e.g. ``temp.db``, to avoid
24 but make sure to change the path to e.g. ``temp.db``, to avoid
25 clobbering any existing database file.
25 clobbering any existing database file.
26
26
27 3. Make your code changes (including database schema changes in ``db.py``).
27 3. Make your code changes (including database schema changes in ``db.py``).
28
28
29 4. After every database schema change, recreate the throwaway database
29 4. After every database schema change, recreate the throwaway database
30 to test the changes::
30 to test the changes::
31
31
32 rm temp.db
32 rm temp.db
33 paster setup-db temp.ini --repos=/var/repos --user=doe --email doe@example.com --password=123456 --no-public-access --force-yes
33 gearbox setup-db -c temp.ini --repos=/var/repos --user=doe --email doe@example.com --password=123456 --no-public-access --force-yes
34 paster repo-scan temp.ini
34 gearbox repo-scan -c temp.ini
35
35
36 5. Once satisfied with the schema changes, auto-generate a draft Alembic
36 5. Once satisfied with the schema changes, auto-generate a draft Alembic
37 script using the development database that has *not* been upgraded.
37 script using the development database that has *not* been upgraded.
38 (The generated script will upgrade the database to match the code.)
38 (The generated script will upgrade the database to match the code.)
39
39
40 ::
40 ::
41
41
42 alembic -c development.ini revision -m "area: add cool feature" --autogenerate
42 alembic -c development.ini revision -m "area: add cool feature" --autogenerate
43
43
44 6. Edit the script to clean it up and fix any problems.
44 6. Edit the script to clean it up and fix any problems.
45
45
46 Note that for changes that simply add columns, it may be appropriate
46 Note that for changes that simply add columns, it may be appropriate
47 to not remove them in the downgrade script (and instead do nothing),
47 to not remove them in the downgrade script (and instead do nothing),
48 to avoid the loss of data. Unknown columns will simply be ignored by
48 to avoid the loss of data. Unknown columns will simply be ignored by
49 Kallithea versions predating your changes.
49 Kallithea versions predating your changes.
50
50
51 7. Run ``alembic -c development.ini upgrade head`` to apply changes to
51 7. Run ``alembic -c development.ini upgrade head`` to apply changes to
52 the (non-throwaway) database, and test the upgrade script. Also test
52 the (non-throwaway) database, and test the upgrade script. Also test
53 downgrades.
53 downgrades.
54
54
55 The included ``development.ini`` has full SQL logging enabled. If
55 The included ``development.ini`` has full SQL logging enabled. If
56 you're using another configuration file, you may want to enable it
56 you're using another configuration file, you may want to enable it
57 by setting ``level = DEBUG`` in section ``[handler_console_sql]``.
57 by setting ``level = DEBUG`` in section ``[handler_console_sql]``.
58
58
59 The Alembic migration script should be committed in the same revision as
59 The Alembic migration script should be committed in the same revision as
60 the database schema (``db.py``) changes.
60 the database schema (``db.py``) changes.
61
61
62 See the `Alembic documentation`__ for more information, in particular
62 See the `Alembic documentation`__ for more information, in particular
63 the tutorial and the section about auto-generating migration scripts.
63 the tutorial and the section about auto-generating migration scripts.
64
64
65 .. __: http://alembic.zzzcomputing.com/en/latest/
65 .. __: http://alembic.zzzcomputing.com/en/latest/
66
66
67
67
68 Troubleshooting
68 Troubleshooting
69 ---------------
69 ---------------
70
70
71 * If ``alembic --autogenerate`` responds "Target database is not up to
71 * If ``alembic --autogenerate`` responds "Target database is not up to
72 date", you need to either first use Alembic to upgrade the database
72 date", you need to either first use Alembic to upgrade the database
73 to the most recent version (before your changes), or recreate the
73 to the most recent version (before your changes), or recreate the
74 database from scratch (without your schema changes applied).
74 database from scratch (without your schema changes applied).
@@ -1,129 +1,129 b''
1 .. _installation_iis:
1 .. _installation_iis:
2
2
3 =====================================================================
3 =====================================================================
4 Installing Kallithea on Microsoft Internet Information Services (IIS)
4 Installing Kallithea on Microsoft Internet Information Services (IIS)
5 =====================================================================
5 =====================================================================
6
6
7 The following is documented using IIS 7/8 terminology. There should be nothing
7 The following is documented using IIS 7/8 terminology. There should be nothing
8 preventing you from applying this on IIS 6 well.
8 preventing you from applying this on IIS 6 well.
9
9
10 .. note::
10 .. note::
11
11
12 Installing Kallithea under IIS can enable Single Sign-On to the Kallithea
12 Installing Kallithea under IIS can enable Single Sign-On to the Kallithea
13 web interface from web browsers that can authenticate to the web server.
13 web interface from web browsers that can authenticate to the web server.
14 (As an alternative to IIS, SSO is also possible with for example Apache and
14 (As an alternative to IIS, SSO is also possible with for example Apache and
15 mod_sspi.)
15 mod_sspi.)
16
16
17 Mercurial and Git do however by default not support SSO on the client side
17 Mercurial and Git do however by default not support SSO on the client side
18 and will still require some other kind of authentication.
18 and will still require some other kind of authentication.
19 (An extension like hgssoauthentication_ might solve that.)
19 (An extension like hgssoauthentication_ might solve that.)
20
20
21 .. note::
21 .. note::
22
22
23 For the best security, it is strongly recommended to only host the site over
23 For the best security, it is strongly recommended to only host the site over
24 a secure connection, e.g. using TLS.
24 a secure connection, e.g. using TLS.
25
25
26
26
27 Prerequisites
27 Prerequisites
28 -------------
28 -------------
29
29
30 Apart from the normal requirements for Kallithea, it is also necessary to get an
30 Apart from the normal requirements for Kallithea, it is also necessary to get an
31 ISAPI-WSGI bridge module, e.g. isapi-wsgi.
31 ISAPI-WSGI bridge module, e.g. isapi-wsgi.
32
32
33
33
34 Installation
34 Installation
35 ------------
35 ------------
36
36
37 The following assumes that your Kallithea is at ``c:\inetpub\kallithea``, and
37 The following assumes that your Kallithea is at ``c:\inetpub\kallithea``, and
38 will be served from the root of its own website. The changes to serve it in its
38 will be served from the root of its own website. The changes to serve it in its
39 own virtual folder will be noted where appropriate.
39 own virtual folder will be noted where appropriate.
40
40
41 Application pool
41 Application pool
42 ^^^^^^^^^^^^^^^^
42 ^^^^^^^^^^^^^^^^
43
43
44 Make sure that there is a unique application pool for the Kallithea application
44 Make sure that there is a unique application pool for the Kallithea application
45 with an identity that has read access to the Kallithea distribution.
45 with an identity that has read access to the Kallithea distribution.
46
46
47 The application pool does not need to be able to run any managed code. If you
47 The application pool does not need to be able to run any managed code. If you
48 are using a 32-bit Python installation, then you must enable 32-bit program in
48 are using a 32-bit Python installation, then you must enable 32-bit program in
49 the advanced settings for the application pool; otherwise Python will not be able
49 the advanced settings for the application pool; otherwise Python will not be able
50 to run on the website and neither will Kallithea.
50 to run on the website and neither will Kallithea.
51
51
52 .. note::
52 .. note::
53
53
54 The application pool can be the same as an existing application pool,
54 The application pool can be the same as an existing application pool,
55 as long as the Kallithea requirements are met by the existing pool.
55 as long as the Kallithea requirements are met by the existing pool.
56
56
57 ISAPI handler
57 ISAPI handler
58 ^^^^^^^^^^^^^
58 ^^^^^^^^^^^^^
59
59
60 The ISAPI handler can be generated using::
60 The ISAPI handler can be generated using::
61
61
62 paster install-iis my.ini --virtualdir=/
62 gearbox install-iis -c my.ini --virtualdir=/
63
63
64 This will generate a ``dispatch.py`` file in the current directory that contains
64 This will generate a ``dispatch.py`` file in the current directory that contains
65 the necessary components to finalize an installation into IIS. Once this file
65 the necessary components to finalize an installation into IIS. Once this file
66 has been generated, it is necessary to run the following command due to the way
66 has been generated, it is necessary to run the following command due to the way
67 that ISAPI-WSGI is made::
67 that ISAPI-WSGI is made::
68
68
69 python2 dispatch.py install
69 python2 dispatch.py install
70
70
71 This accomplishes two things: generating an ISAPI compliant DLL file,
71 This accomplishes two things: generating an ISAPI compliant DLL file,
72 ``_dispatch.dll``, and installing a script map handler into IIS for the
72 ``_dispatch.dll``, and installing a script map handler into IIS for the
73 ``--virtualdir`` specified above pointing to ``_dispatch.dll``.
73 ``--virtualdir`` specified above pointing to ``_dispatch.dll``.
74
74
75 The ISAPI handler is registered to all file extensions, so it will automatically
75 The ISAPI handler is registered to all file extensions, so it will automatically
76 be the one handling all requests to the specified virtual directory. When the website starts
76 be the one handling all requests to the specified virtual directory. When the website starts
77 the ISAPI handler, it will start a thread pool managed wrapper around the paster
77 the ISAPI handler, it will start a thread pool managed wrapper around the
78 middleware WSGI handler that Kallithea runs within and each HTTP request to the
78 middleware WSGI handler that Kallithea runs within and each HTTP request to the
79 site will be processed through this logic henceforth.
79 site will be processed through this logic henceforth.
80
80
81 Authentication with Kallithea using IIS authentication modules
81 Authentication with Kallithea using IIS authentication modules
82 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
82 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
83
83
84 The recommended way to handle authentication with Kallithea using IIS is to let
84 The recommended way to handle authentication with Kallithea using IIS is to let
85 IIS handle all the authentication and just pass it to Kallithea.
85 IIS handle all the authentication and just pass it to Kallithea.
86
86
87 .. note::
87 .. note::
88
88
89 As an alternative without SSO, you can also use LDAP authentication with
89 As an alternative without SSO, you can also use LDAP authentication with
90 Active Directory, see :ref:`ldap-setup`.
90 Active Directory, see :ref:`ldap-setup`.
91
91
92 To move responsibility into IIS from Kallithea, we need to configure Kallithea
92 To move responsibility into IIS from Kallithea, we need to configure Kallithea
93 to let external systems handle authentication and then let Kallithea create the
93 to let external systems handle authentication and then let Kallithea create the
94 user automatically. To do this, access the administration's authentication page
94 user automatically. To do this, access the administration's authentication page
95 and enable the ``kallithea.lib.auth_modules.auth_container`` plugin. Once it is
95 and enable the ``kallithea.lib.auth_modules.auth_container`` plugin. Once it is
96 added, enable it with the ``REMOTE_USER`` header and check *Clean username*.
96 added, enable it with the ``REMOTE_USER`` header and check *Clean username*.
97 Finally, save the changes on this page.
97 Finally, save the changes on this page.
98
98
99 Switch to the administration's permissions page and disable anonymous access,
99 Switch to the administration's permissions page and disable anonymous access,
100 otherwise Kallithea will not attempt to use the authenticated user name. By
100 otherwise Kallithea will not attempt to use the authenticated user name. By
101 default, Kallithea will populate the list of users lazily as they log in. Either
101 default, Kallithea will populate the list of users lazily as they log in. Either
102 disable external auth account activation and ensure that you pre-populate the
102 disable external auth account activation and ensure that you pre-populate the
103 user database with an external tool, or set it to *Automatic activation of
103 user database with an external tool, or set it to *Automatic activation of
104 external account*. Finally, save the changes.
104 external account*. Finally, save the changes.
105
105
106 The last necessary step is to enable the relevant authentication in IIS, e.g.
106 The last necessary step is to enable the relevant authentication in IIS, e.g.
107 Windows authentication.
107 Windows authentication.
108
108
109
109
110 Troubleshooting
110 Troubleshooting
111 ---------------
111 ---------------
112
112
113 Typically, any issues in this setup will either be entirely in IIS or entirely
113 Typically, any issues in this setup will either be entirely in IIS or entirely
114 in Kallithea (or Kallithea's WSGI/paster middleware). Consequently, two
114 in Kallithea (or Kallithea's WSGI middleware). Consequently, two
115 different options for finding issues exist: IIS' failed request tracking which
115 different options for finding issues exist: IIS' failed request tracking which
116 is great at finding issues until they exist inside Kallithea, at which point the
116 is great at finding issues until they exist inside Kallithea, at which point the
117 ISAPI-WSGI wrapper above uses ``win32traceutil``, which is part of ``pywin32``.
117 ISAPI-WSGI wrapper above uses ``win32traceutil``, which is part of ``pywin32``.
118
118
119 In order to dump output from WSGI using ``win32traceutil`` it is sufficient to
119 In order to dump output from WSGI using ``win32traceutil`` it is sufficient to
120 type the following in a console window::
120 type the following in a console window::
121
121
122 python2 -m win32traceutil
122 python2 -m win32traceutil
123
123
124 and any exceptions occurring in the WSGI layer and below (i.e. in the Kallithea
124 and any exceptions occurring in the WSGI layer and below (i.e. in the Kallithea
125 application itself) that are uncaught, will be printed here complete with stack
125 application itself) that are uncaught, will be printed here complete with stack
126 traces, making it a lot easier to identify issues.
126 traces, making it a lot easier to identify issues.
127
127
128
128
129 .. _hgssoauthentication: https://bitbucket.org/domruf/hgssoauthentication
129 .. _hgssoauthentication: https://bitbucket.org/domruf/hgssoauthentication
@@ -1,223 +1,223 b''
1 .. _installation_win:
1 .. _installation_win:
2
2
3 ====================================================
3 ====================================================
4 Installation on Windows (7/Server 2008 R2 and newer)
4 Installation on Windows (7/Server 2008 R2 and newer)
5 ====================================================
5 ====================================================
6
6
7
7
8 First time install
8 First time install
9 ------------------
9 ------------------
10
10
11 Target OS: Windows 7 and newer or Windows Server 2008 R2 and newer
11 Target OS: Windows 7 and newer or Windows Server 2008 R2 and newer
12
12
13 Tested on Windows 8.1, Windows Server 2008 R2 and Windows Server 2012
13 Tested on Windows 8.1, Windows Server 2008 R2 and Windows Server 2012
14
14
15 To install on an older version of Windows, see `<installation_win_old.html>`_
15 To install on an older version of Windows, see `<installation_win_old.html>`_
16
16
17 Step 1 -- Install Python
17 Step 1 -- Install Python
18 ^^^^^^^^^^^^^^^^^^^^^^^^
18 ^^^^^^^^^^^^^^^^^^^^^^^^
19
19
20 Install Python 2.x.y (x = 6 or 7). Latest version is recommended. If you need another version, they can run side by side.
20 Install Python 2.x.y (x = 6 or 7). Latest version is recommended. If you need another version, they can run side by side.
21
21
22 .. warning:: Python 3.x is not supported.
22 .. warning:: Python 3.x is not supported.
23
23
24 - Download Python 2.x.y from http://www.python.org/download/
24 - Download Python 2.x.y from http://www.python.org/download/
25 - Choose and click on the version
25 - Choose and click on the version
26 - Click on "Windows X86-64 Installer" for x64 or "Windows x86 MSI installer" for Win32.
26 - Click on "Windows X86-64 Installer" for x64 or "Windows x86 MSI installer" for Win32.
27 - Disable UAC or run the installer with admin privileges. If you chose to disable UAC, do not forget to reboot afterwards.
27 - Disable UAC or run the installer with admin privileges. If you chose to disable UAC, do not forget to reboot afterwards.
28
28
29 While writing this guide, the latest version was v2.7.9.
29 While writing this guide, the latest version was v2.7.9.
30 Remember the specific major and minor versions installed, because they will
30 Remember the specific major and minor versions installed, because they will
31 be needed in the next step. In this case, it is "2.7".
31 be needed in the next step. In this case, it is "2.7".
32
32
33 Step 2 -- Python BIN
33 Step 2 -- Python BIN
34 ^^^^^^^^^^^^^^^^^^^^
34 ^^^^^^^^^^^^^^^^^^^^
35
35
36 Add Python BIN folder to the path. This can be done manually (editing
36 Add Python BIN folder to the path. This can be done manually (editing
37 "PATH" environment variable) or by using Windows Support Tools that
37 "PATH" environment variable) or by using Windows Support Tools that
38 come pre-installed in Windows Vista/7 and later.
38 come pre-installed in Windows Vista/7 and later.
39
39
40 Open a CMD and type::
40 Open a CMD and type::
41
41
42 SETX PATH "%PATH%;[your-python-path]" /M
42 SETX PATH "%PATH%;[your-python-path]" /M
43
43
44 Please substitute [your-python-path] with your Python installation
44 Please substitute [your-python-path] with your Python installation
45 path. Typically this is ``C:\\Python27``.
45 path. Typically this is ``C:\\Python27``.
46
46
47 Step 3 -- Install pywin32 extensions
47 Step 3 -- Install pywin32 extensions
48 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
48 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
49
49
50 Download pywin32 from:
50 Download pywin32 from:
51 http://sourceforge.net/projects/pywin32/files/
51 http://sourceforge.net/projects/pywin32/files/
52
52
53 - Click on "pywin32" folder
53 - Click on "pywin32" folder
54 - Click on the first folder (in this case, Build 219, maybe newer when you try)
54 - Click on the first folder (in this case, Build 219, maybe newer when you try)
55 - Choose the file ending with ".amd64-py2.x.exe" (".win32-py2.x.exe"
55 - Choose the file ending with ".amd64-py2.x.exe" (".win32-py2.x.exe"
56 for Win32) where x is the minor version of Python you installed.
56 for Win32) where x is the minor version of Python you installed.
57 When writing this guide, the file was:
57 When writing this guide, the file was:
58 http://sourceforge.net/projects/pywin32/files/pywin32/Build%20219/pywin32-219.win-amd64-py2.7.exe/download
58 http://sourceforge.net/projects/pywin32/files/pywin32/Build%20219/pywin32-219.win-amd64-py2.7.exe/download
59 (x64)
59 (x64)
60 http://sourceforge.net/projects/pywin32/files/pywin32/Build%20219/pywin32-219.win32-py2.7.exe/download
60 http://sourceforge.net/projects/pywin32/files/pywin32/Build%20219/pywin32-219.win32-py2.7.exe/download
61 (Win32)
61 (Win32)
62
62
63 Step 4 -- Install pip
63 Step 4 -- Install pip
64 ^^^^^^^^^^^^^^^^^^^^^
64 ^^^^^^^^^^^^^^^^^^^^^
65
65
66 pip is a package management system for Python. You will need it to install Kallithea and its dependencies.
66 pip is a package management system for Python. You will need it to install Kallithea and its dependencies.
67
67
68 If you installed Python 2.7.9+, you already have it (as long as you ran the installer with admin privileges or disabled UAC).
68 If you installed Python 2.7.9+, you already have it (as long as you ran the installer with admin privileges or disabled UAC).
69
69
70 If it was not installed or if you are using Python>=2.6,<2.7.9:
70 If it was not installed or if you are using Python>=2.6,<2.7.9:
71
71
72 - Go to https://bootstrap.pypa.io
72 - Go to https://bootstrap.pypa.io
73 - Right-click on get-pip.py and choose Saves as...
73 - Right-click on get-pip.py and choose Saves as...
74 - Run "python2 get-pip.py" in the folder where you downloaded get-pip.py (may require admin access).
74 - Run "python2 get-pip.py" in the folder where you downloaded get-pip.py (may require admin access).
75
75
76 .. note::
76 .. note::
77
77
78 See http://stackoverflow.com/questions/4750806/how-to-install-pip-on-windows
78 See http://stackoverflow.com/questions/4750806/how-to-install-pip-on-windows
79 for details and alternative methods.
79 for details and alternative methods.
80
80
81 Note that pip.exe will be placed inside your Python installation's
81 Note that pip.exe will be placed inside your Python installation's
82 Scripts folder, which is likely not on your path. To correct this,
82 Scripts folder, which is likely not on your path. To correct this,
83 open a CMD and type::
83 open a CMD and type::
84
84
85 SETX PATH "%PATH%;[your-python-path]\Scripts" /M
85 SETX PATH "%PATH%;[your-python-path]\Scripts" /M
86
86
87 Step 5 -- Kallithea folder structure
87 Step 5 -- Kallithea folder structure
88 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
88 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
89
89
90 Create a Kallithea folder structure.
90 Create a Kallithea folder structure.
91
91
92 This is only an example to install Kallithea. Of course, you can
92 This is only an example to install Kallithea. Of course, you can
93 change it. However, this guide will follow the proposed structure, so
93 change it. However, this guide will follow the proposed structure, so
94 please later adapt the paths if you change them. Folders without
94 please later adapt the paths if you change them. Folders without
95 spaces are recommended.
95 spaces are recommended.
96
96
97 Create the following folder structure::
97 Create the following folder structure::
98
98
99 C:\Kallithea
99 C:\Kallithea
100 C:\Kallithea\Bin
100 C:\Kallithea\Bin
101 C:\Kallithea\Env
101 C:\Kallithea\Env
102 C:\Kallithea\Repos
102 C:\Kallithea\Repos
103
103
104 Step 6 -- Install virtualenv
104 Step 6 -- Install virtualenv
105 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
105 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
106
106
107 .. note::
107 .. note::
108 A python virtual environment will allow for isolation between the Python packages of your system and those used for Kallithea.
108 A python virtual environment will allow for isolation between the Python packages of your system and those used for Kallithea.
109 It is strongly recommended to use it to ensure that Kallithea does not change a dependency that other software uses or vice versa.
109 It is strongly recommended to use it to ensure that Kallithea does not change a dependency that other software uses or vice versa.
110
110
111 In a command prompt type::
111 In a command prompt type::
112
112
113 pip install virtualenv
113 pip install virtualenv
114
114
115 Virtualenv will now be inside your Python Scripts path (C:\\Python27\\Scripts or similar).
115 Virtualenv will now be inside your Python Scripts path (C:\\Python27\\Scripts or similar).
116
116
117 To create a virtual environment, run::
117 To create a virtual environment, run::
118
118
119 virtualenv C:\Kallithea\Env
119 virtualenv C:\Kallithea\Env
120
120
121 Step 7 -- Install Kallithea
121 Step 7 -- Install Kallithea
122 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
122 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
123
123
124 In order to install Kallithea, you need to be able to run "pip install kallithea". It will use pip to install the Kallithea Python package and its dependencies.
124 In order to install Kallithea, you need to be able to run "pip install kallithea". It will use pip to install the Kallithea Python package and its dependencies.
125 Some Python packages use managed code and need to be compiled.
125 Some Python packages use managed code and need to be compiled.
126 This can be done on Linux without any special steps. On Windows, you will need to install Microsoft Visual C++ compiler for Python 2.7.
126 This can be done on Linux without any special steps. On Windows, you will need to install Microsoft Visual C++ compiler for Python 2.7.
127
127
128 Download and install "Microsoft Visual C++ Compiler for Python 2.7" from http://aka.ms/vcpython27
128 Download and install "Microsoft Visual C++ Compiler for Python 2.7" from http://aka.ms/vcpython27
129
129
130 .. note::
130 .. note::
131 You can also install the dependencies using already compiled Windows binaries packages. A good source of compiled Python packages is http://www.lfd.uci.edu/~gohlke/pythonlibs/. However, not all of the necessary packages for Kallithea are on this site and some are hard to find, so we will stick with using the compiler.
131 You can also install the dependencies using already compiled Windows binaries packages. A good source of compiled Python packages is http://www.lfd.uci.edu/~gohlke/pythonlibs/. However, not all of the necessary packages for Kallithea are on this site and some are hard to find, so we will stick with using the compiler.
132
132
133 In a command prompt type (adapting paths if necessary)::
133 In a command prompt type (adapting paths if necessary)::
134
134
135 cd C:\Kallithea\Env\Scripts
135 cd C:\Kallithea\Env\Scripts
136 activate
136 activate
137 pip install --upgrade pip setuptools
137 pip install --upgrade pip setuptools
138
138
139 The prompt will change into "(Env) C:\\Kallithea\\Env\\Scripts" or similar
139 The prompt will change into "(Env) C:\\Kallithea\\Env\\Scripts" or similar
140 (depending of your folder structure). Then type::
140 (depending of your folder structure). Then type::
141
141
142 pip install kallithea
142 pip install kallithea
143
143
144 .. note:: This will take some time. Please wait patiently until it is fully
144 .. note:: This will take some time. Please wait patiently until it is fully
145 complete. Some warnings will appear. Don't worry, they are
145 complete. Some warnings will appear. Don't worry, they are
146 normal.
146 normal.
147
147
148 Step 8 -- Install Git (optional)
148 Step 8 -- Install Git (optional)
149 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
149 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
150
150
151 Mercurial being a python package, was installed automatically when doing ``pip install kallithea``.
151 Mercurial being a python package, was installed automatically when doing ``pip install kallithea``.
152
152
153 You need to install Git manually if you want Kallithea to be able to host Git repositories.
153 You need to install Git manually if you want Kallithea to be able to host Git repositories.
154 See http://git-scm.com/book/en/v2/Getting-Started-Installing-Git#Installing-on-Windows for instructions.
154 See http://git-scm.com/book/en/v2/Getting-Started-Installing-Git#Installing-on-Windows for instructions.
155 The location of the Git binaries (like ``c:\path\to\git\bin``) must be
155 The location of the Git binaries (like ``c:\path\to\git\bin``) must be
156 added to the ``PATH`` environment variable so ``git.exe`` and other tools like
156 added to the ``PATH`` environment variable so ``git.exe`` and other tools like
157 ``gzip.exe`` are available.
157 ``gzip.exe`` are available.
158
158
159 Step 9 -- Configuring Kallithea
159 Step 9 -- Configuring Kallithea
160 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
160 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
161
161
162 Steps taken from `<setup.html>`_
162 Steps taken from `<setup.html>`_
163
163
164 You have to use the same command prompt as in Step 7, so if you closed
164 You have to use the same command prompt as in Step 7, so if you closed
165 it, reopen it following the same commands (including the "activate"
165 it, reopen it following the same commands (including the "activate"
166 one). When ready, type::
166 one). When ready, type::
167
167
168 cd C:\Kallithea\Bin
168 cd C:\Kallithea\Bin
169 paster make-config Kallithea production.ini
169 TODO make-config Kallithea production.ini
170
170
171 Then you must edit production.ini to fit your needs (IP address, IP
171 Then you must edit production.ini to fit your needs (IP address, IP
172 port, mail settings, database, etc.). `NotePad++`__ or a similar text
172 port, mail settings, database, etc.). `NotePad++`__ or a similar text
173 editor is recommended to properly handle the newline character
173 editor is recommended to properly handle the newline character
174 differences between Unix and Windows.
174 differences between Unix and Windows.
175
175
176 __ http://notepad-plus-plus.org/
176 __ http://notepad-plus-plus.org/
177
177
178 For the sake of simplicity, run it with the default settings. After your edits (if any) in the previous command prompt, type::
178 For the sake of simplicity, run it with the default settings. After your edits (if any) in the previous command prompt, type::
179
179
180 paster setup-db production.ini
180 gearbox setup-db -c production.ini
181
181
182 .. warning:: This time a *new* database will be installed. You must
182 .. warning:: This time a *new* database will be installed. You must
183 follow a different process to later :ref:`upgrade <upgrade>`
183 follow a different process to later :ref:`upgrade <upgrade>`
184 to a newer Kallithea version.
184 to a newer Kallithea version.
185
185
186 The script will ask you for confirmation about creating a new database, answer yes (y)
186 The script will ask you for confirmation about creating a new database, answer yes (y)
187
187
188 The script will ask you for the repository path, answer C:\\Kallithea\\Repos (or similar).
188 The script will ask you for the repository path, answer C:\\Kallithea\\Repos (or similar).
189
189
190 The script will ask you for the admin username and password, answer "admin" + "123456" (or whatever you want)
190 The script will ask you for the admin username and password, answer "admin" + "123456" (or whatever you want)
191
191
192 The script will ask you for admin mail, answer "admin@xxxx.com" (or whatever you want).
192 The script will ask you for admin mail, answer "admin@xxxx.com" (or whatever you want).
193
193
194 If you make a mistake and the script doesn't end, don't worry: start it again.
194 If you make a mistake and the script doesn't end, don't worry: start it again.
195
195
196 If you decided not to install Git, you will get errors about it that you can ignore.
196 If you decided not to install Git, you will get errors about it that you can ignore.
197
197
198 Step 10 -- Running Kallithea
198 Step 10 -- Running Kallithea
199 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
199 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
200
200
201 In the previous command prompt, being in the C:\\Kallithea\\Bin folder, type::
201 In the previous command prompt, being in the C:\\Kallithea\\Bin folder, type::
202
202
203 paster serve production.ini
203 gearbox serve -c production.ini
204
204
205 Open your web server, and go to http://127.0.0.1:5000
205 Open your web server, and go to http://127.0.0.1:5000
206
206
207 It works!! :-)
207 It works!! :-)
208
208
209 Remark:
209 Remark:
210 If it does not work the first time, Ctrl-C the CMD process and start it again. Don't forget the "http://" in Internet Explorer.
210 If it does not work the first time, Ctrl-C the CMD process and start it again. Don't forget the "http://" in Internet Explorer.
211
211
212 What this guide does not cover:
212 What this guide does not cover:
213
213
214 - Installing Celery
214 - Installing Celery
215 - Running Kallithea as a Windows Service. You can investigate here:
215 - Running Kallithea as a Windows Service. You can investigate here:
216
216
217 - http://pypi.python.org/pypi/wsgisvc
217 - http://pypi.python.org/pypi/wsgisvc
218 - http://ryrobes.com/python/running-python-scripts-as-a-windows-service/
218 - http://ryrobes.com/python/running-python-scripts-as-a-windows-service/
219 - http://wiki.pylonshq.com/display/pylonscookbook/How+to+run+Pylons+as+a+Windows+service
219 - http://wiki.pylonshq.com/display/pylonscookbook/How+to+run+Pylons+as+a+Windows+service
220
220
221 - Using Apache. You can investigate here:
221 - Using Apache. You can investigate here:
222
222
223 - https://groups.google.com/group/rhodecode/msg/c433074e813ffdc4
223 - https://groups.google.com/group/rhodecode/msg/c433074e813ffdc4
@@ -1,263 +1,263 b''
1 .. _installation_win_old:
1 .. _installation_win_old:
2
2
3 ==========================================================
3 ==========================================================
4 Installation on Windows (XP/Vista/Server 2003/Server 2008)
4 Installation on Windows (XP/Vista/Server 2003/Server 2008)
5 ==========================================================
5 ==========================================================
6
6
7
7
8 First-time install
8 First-time install
9 ------------------
9 ------------------
10
10
11 Target OS: Windows XP SP3 32-bit English (Clean installation)
11 Target OS: Windows XP SP3 32-bit English (Clean installation)
12 + All Windows Updates until 24-may-2012
12 + All Windows Updates until 24-may-2012
13
13
14 .. note::
14 .. note::
15
15
16 This installation is for 32-bit systems, for 64-bit Windows you might need
16 This installation is for 32-bit systems, for 64-bit Windows you might need
17 to download proper 64-bit versions of the different packages (Windows Installer, Win32py extensions)
17 to download proper 64-bit versions of the different packages (Windows Installer, Win32py extensions)
18 plus some extra tweaks.
18 plus some extra tweaks.
19 These extra steps haven been marked as "64-bit".
19 These extra steps haven been marked as "64-bit".
20 Tested on Windows Server 2008 R2 SP1, 9-feb-2013.
20 Tested on Windows Server 2008 R2 SP1, 9-feb-2013.
21 If you run into any 64-bit related problems, please check these pages:
21 If you run into any 64-bit related problems, please check these pages:
22
22
23 - http://blog.victorjabur.com/2011/06/05/compiling-python-2-7-modules-on-windows-32-and-64-using-msvc-2008-express/
23 - http://blog.victorjabur.com/2011/06/05/compiling-python-2-7-modules-on-windows-32-and-64-using-msvc-2008-express/
24 - http://bugs.python.org/issue7511
24 - http://bugs.python.org/issue7511
25
25
26 Step 1 -- Install Visual Studio 2008 Express
26 Step 1 -- Install Visual Studio 2008 Express
27 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
27 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
28
28
29 Optional: You can also install MinGW, but VS2008 installation is easier.
29 Optional: You can also install MinGW, but VS2008 installation is easier.
30
30
31 Download "Visual C++ 2008 Express Edition with SP1" from:
31 Download "Visual C++ 2008 Express Edition with SP1" from:
32 http://download.microsoft.com/download/E/8/E/E8EEB394-7F42-4963-A2D8-29559B738298/VS2008ExpressWithSP1ENUX1504728.iso
32 http://download.microsoft.com/download/E/8/E/E8EEB394-7F42-4963-A2D8-29559B738298/VS2008ExpressWithSP1ENUX1504728.iso
33 (if not found or relocated, google for "visual studio 2008 express" for updated link. This link was taken from http://stackoverflow.com/questions/15318560/visual-c-2008-express-download-link-dead)
33 (if not found or relocated, google for "visual studio 2008 express" for updated link. This link was taken from http://stackoverflow.com/questions/15318560/visual-c-2008-express-download-link-dead)
34
34
35 You can also download full ISO file for offline installation, just
35 You can also download full ISO file for offline installation, just
36 choose "All -- Offline Install ISO image file" in the previous page and
36 choose "All -- Offline Install ISO image file" in the previous page and
37 choose "Visual C++ 2008 Express" when installing.
37 choose "Visual C++ 2008 Express" when installing.
38
38
39 .. note::
39 .. note::
40
40
41 Using other versions of Visual Studio will lead to random crashes.
41 Using other versions of Visual Studio will lead to random crashes.
42 You must use Visual Studio 2008!"
42 You must use Visual Studio 2008!"
43
43
44 .. note::
44 .. note::
45
45
46 Silverlight Runtime and SQL Server 2008 Express Edition are not
46 Silverlight Runtime and SQL Server 2008 Express Edition are not
47 required, you can uncheck them
47 required, you can uncheck them
48
48
49 .. note::
49 .. note::
50
50
51 64-bit: You also need to install the Microsoft Windows SDK for .NET 3.5 SP1 (.NET 4.0 won't work).
51 64-bit: You also need to install the Microsoft Windows SDK for .NET 3.5 SP1 (.NET 4.0 won't work).
52 Download from: http://www.microsoft.com/en-us/download/details.aspx?id=3138
52 Download from: http://www.microsoft.com/en-us/download/details.aspx?id=3138
53
53
54 .. note::
54 .. note::
55
55
56 64-bit: You also need to copy and rename a .bat file to make the Visual C++ compiler work.
56 64-bit: You also need to copy and rename a .bat file to make the Visual C++ compiler work.
57 I am not sure why this is not necessary for 32-bit.
57 I am not sure why this is not necessary for 32-bit.
58 Copy C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat to C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\amd64\vcvarsamd64.bat
58 Copy C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat to C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\amd64\vcvarsamd64.bat
59
59
60 Step 2 -- Install Python
60 Step 2 -- Install Python
61 ^^^^^^^^^^^^^^^^^^^^^^^^
61 ^^^^^^^^^^^^^^^^^^^^^^^^
62
62
63 Install Python 2.x.y (x = 6 or 7) x86 version (32-bit). DO NOT USE A 3.x version.
63 Install Python 2.x.y (x = 6 or 7) x86 version (32-bit). DO NOT USE A 3.x version.
64 Download Python 2.x.y from:
64 Download Python 2.x.y from:
65 http://www.python.org/download/
65 http://www.python.org/download/
66
66
67 Choose "Windows Installer" (32-bit version) not "Windows X86-64
67 Choose "Windows Installer" (32-bit version) not "Windows X86-64
68 Installer". While writing this guide, the latest version was v2.7.3.
68 Installer". While writing this guide, the latest version was v2.7.3.
69 Remember the specific major and minor version installed, because it will
69 Remember the specific major and minor version installed, because it will
70 be needed in the next step. In this case, it is "2.7".
70 be needed in the next step. In this case, it is "2.7".
71
71
72 .. note::
72 .. note::
73
73
74 64-bit: Just download and install the 64-bit version of python.
74 64-bit: Just download and install the 64-bit version of python.
75
75
76 Step 3 -- Install Win32py extensions
76 Step 3 -- Install Win32py extensions
77 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
77 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
78
78
79 Download pywin32 from:
79 Download pywin32 from:
80 http://sourceforge.net/projects/pywin32/files/
80 http://sourceforge.net/projects/pywin32/files/
81
81
82 - Click on "pywin32" folder
82 - Click on "pywin32" folder
83 - Click on the first folder (in this case, Build 217, maybe newer when you try)
83 - Click on the first folder (in this case, Build 217, maybe newer when you try)
84 - Choose the file ending with ".win32-py2.x.exe" -> x being the minor
84 - Choose the file ending with ".win32-py2.x.exe" -> x being the minor
85 version of Python you installed (in this case, 7)
85 version of Python you installed (in this case, 7)
86 When writing this guide, the file was:
86 When writing this guide, the file was:
87 http://sourceforge.net/projects/pywin32/files/pywin32/Build%20217/pywin32-217.win32-py2.7.exe/download
87 http://sourceforge.net/projects/pywin32/files/pywin32/Build%20217/pywin32-217.win32-py2.7.exe/download
88
88
89 .. note::
89 .. note::
90
90
91 64-bit: Download and install the 64-bit version.
91 64-bit: Download and install the 64-bit version.
92 At the time of writing you can find this at:
92 At the time of writing you can find this at:
93 http://sourceforge.net/projects/pywin32/files/pywin32/Build%20218/pywin32-218.win-amd64-py2.7.exe/download
93 http://sourceforge.net/projects/pywin32/files/pywin32/Build%20218/pywin32-218.win-amd64-py2.7.exe/download
94
94
95 Step 4 -- Python BIN
95 Step 4 -- Python BIN
96 ^^^^^^^^^^^^^^^^^^^^
96 ^^^^^^^^^^^^^^^^^^^^
97
97
98 Add Python BIN folder to the path
98 Add Python BIN folder to the path
99
99
100 You have to add the Python folder to the path, you can do it manually
100 You have to add the Python folder to the path, you can do it manually
101 (editing "PATH" environment variable) or using Windows Support Tools
101 (editing "PATH" environment variable) or using Windows Support Tools
102 that came preinstalled in Vista/7 and can be installed in Windows XP.
102 that came preinstalled in Vista/7 and can be installed in Windows XP.
103
103
104 - Using support tools on WINDOWS XP:
104 - Using support tools on WINDOWS XP:
105 If you use Windows XP you can install them using Windows XP CD and
105 If you use Windows XP you can install them using Windows XP CD and
106 navigating to \SUPPORT\TOOLS. There, execute Setup.EXE (not MSI).
106 navigating to \SUPPORT\TOOLS. There, execute Setup.EXE (not MSI).
107 Afterwards, open a CMD and type::
107 Afterwards, open a CMD and type::
108
108
109 SETX PATH "%PATH%;[your-python-path]" -M
109 SETX PATH "%PATH%;[your-python-path]" -M
110
110
111 Close CMD (the path variable will be updated then)
111 Close CMD (the path variable will be updated then)
112
112
113 - Using support tools on WINDOWS Vista/7:
113 - Using support tools on WINDOWS Vista/7:
114
114
115 Open a CMD and type::
115 Open a CMD and type::
116
116
117 SETX PATH "%PATH%;[your-python-path]" /M
117 SETX PATH "%PATH%;[your-python-path]" /M
118
118
119 Please substitute [your-python-path] with your Python installation path.
119 Please substitute [your-python-path] with your Python installation path.
120 Typically: C:\\Python27
120 Typically: C:\\Python27
121
121
122 Step 5 -- Kallithea folder structure
122 Step 5 -- Kallithea folder structure
123 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
123 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
124
124
125 Create a Kallithea folder structure
125 Create a Kallithea folder structure
126
126
127 This is only a example to install Kallithea, you can of course change
127 This is only a example to install Kallithea, you can of course change
128 it. However, this guide will follow the proposed structure, so please
128 it. However, this guide will follow the proposed structure, so please
129 later adapt the paths if you change them. My recommendation is to use
129 later adapt the paths if you change them. My recommendation is to use
130 folders with NO SPACES. But you can try if you are brave...
130 folders with NO SPACES. But you can try if you are brave...
131
131
132 Create the following folder structure::
132 Create the following folder structure::
133
133
134 C:\Kallithea
134 C:\Kallithea
135 C:\Kallithea\Bin
135 C:\Kallithea\Bin
136 C:\Kallithea\Env
136 C:\Kallithea\Env
137 C:\Kallithea\Repos
137 C:\Kallithea\Repos
138
138
139 Step 6 -- Install virtualenv
139 Step 6 -- Install virtualenv
140 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
140 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
141
141
142 Install Virtual Env for Python
142 Install Virtual Env for Python
143
143
144 Navigate to: http://www.virtualenv.org/en/latest/index.html#installation
144 Navigate to: http://www.virtualenv.org/en/latest/index.html#installation
145 Right click on "virtualenv.py" file and choose "Save link as...".
145 Right click on "virtualenv.py" file and choose "Save link as...".
146 Download to C:\\Kallithea (or whatever you want)
146 Download to C:\\Kallithea (or whatever you want)
147 (the file is located at
147 (the file is located at
148 https://raw.github.com/pypa/virtualenv/master/virtualenv.py)
148 https://raw.github.com/pypa/virtualenv/master/virtualenv.py)
149
149
150 Create a virtual Python environment in C:\\Kallithea\\Env (or similar). To
150 Create a virtual Python environment in C:\\Kallithea\\Env (or similar). To
151 do so, open a CMD (Python Path should be included in Step3), navigate
151 do so, open a CMD (Python Path should be included in Step3), navigate
152 where you downloaded "virtualenv.py", and write::
152 where you downloaded "virtualenv.py", and write::
153
153
154 python2 virtualenv.py C:\Kallithea\Env
154 python2 virtualenv.py C:\Kallithea\Env
155
155
156 (--no-site-packages is now the default behaviour of virtualenv, no need
156 (--no-site-packages is now the default behaviour of virtualenv, no need
157 to include it)
157 to include it)
158
158
159 Step 7 -- Install Kallithea
159 Step 7 -- Install Kallithea
160 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
160 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
161
161
162 Finally, install Kallithea
162 Finally, install Kallithea
163
163
164 Close previously opened command prompt/s, and open a Visual Studio 2008
164 Close previously opened command prompt/s, and open a Visual Studio 2008
165 Command Prompt (**IMPORTANT!!**). To do so, go to Start Menu, and then open
165 Command Prompt (**IMPORTANT!!**). To do so, go to Start Menu, and then open
166 "Microsoft Visual C++ 2008 Express Edition" -> "Visual Studio Tools" ->
166 "Microsoft Visual C++ 2008 Express Edition" -> "Visual Studio Tools" ->
167 "Visual Studio 2008 Command Prompt"
167 "Visual Studio 2008 Command Prompt"
168
168
169 .. note::
169 .. note::
170
170
171 64-bit: For 64-bit you need to modify the shortcut that is used to start the
171 64-bit: For 64-bit you need to modify the shortcut that is used to start the
172 Visual Studio 2008 Command Prompt. Use right-mouse click to open properties.
172 Visual Studio 2008 Command Prompt. Use right-mouse click to open properties.
173
173
174 Change commandline from::
174 Change commandline from::
175
175
176 %comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"" x86
176 %comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"" x86
177
177
178 to::
178 to::
179
179
180 %comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"" amd64
180 %comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"" amd64
181
181
182 In that CMD (loaded with VS2008 PATHs) type::
182 In that CMD (loaded with VS2008 PATHs) type::
183
183
184 cd C:\Kallithea\Env\Scripts (or similar)
184 cd C:\Kallithea\Env\Scripts (or similar)
185 activate
185 activate
186 pip install --upgrade pip setuptools
186 pip install --upgrade pip setuptools
187
187
188 The prompt will change into "(Env) C:\\Kallithea\\Env\\Scripts" or similar
188 The prompt will change into "(Env) C:\\Kallithea\\Env\\Scripts" or similar
189 (depending of your folder structure). Then type::
189 (depending of your folder structure). Then type::
190
190
191 pip install kallithea
191 pip install kallithea
192
192
193 (long step, please wait until fully complete)
193 (long step, please wait until fully complete)
194
194
195 Some warnings will appear, don't worry as they are normal.
195 Some warnings will appear, don't worry as they are normal.
196
196
197 Step 8 -- Configuring Kallithea
197 Step 8 -- Configuring Kallithea
198 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
198 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
199
199
200 steps taken from http://packages.python.org/Kallithea/setup.html
200 steps taken from http://packages.python.org/Kallithea/setup.html
201
201
202 You have to use the same Visual Studio 2008 command prompt as Step7, so
202 You have to use the same Visual Studio 2008 command prompt as Step7, so
203 if you closed it reopen it following the same commands (including the
203 if you closed it reopen it following the same commands (including the
204 "activate" one). When ready, just type::
204 "activate" one). When ready, just type::
205
205
206 cd C:\Kallithea\Bin
206 cd C:\Kallithea\Bin
207 paster make-config Kallithea production.ini
207 TODO make-config Kallithea production.ini
208
208
209 Then, you must edit production.ini to fit your needs (network address and
209 Then, you must edit production.ini to fit your needs (network address and
210 port, mail settings, database, whatever). I recommend using NotePad++
210 port, mail settings, database, whatever). I recommend using NotePad++
211 (free) or similar text editor, as it handles well the EndOfLine
211 (free) or similar text editor, as it handles well the EndOfLine
212 character differences between Unix and Windows
212 character differences between Unix and Windows
213 (http://notepad-plus-plus.org/)
213 (http://notepad-plus-plus.org/)
214
214
215 For the sake of simplicity lets run it with the default settings. After
215 For the sake of simplicity lets run it with the default settings. After
216 your edits (if any), in the previous Command Prompt, type::
216 your edits (if any), in the previous Command Prompt, type::
217
217
218 paster setup-db production.ini
218 gearbox setup-db -c production.ini
219
219
220 .. warning:: This time a *new* database will be installed. You must
220 .. warning:: This time a *new* database will be installed. You must
221 follow a different process to later :ref:`upgrade <upgrade>`
221 follow a different process to later :ref:`upgrade <upgrade>`
222 to a newer Kallithea version.
222 to a newer Kallithea version.
223
223
224 The script will ask you for confirmation about creating a NEW database,
224 The script will ask you for confirmation about creating a NEW database,
225 answer yes (y)
225 answer yes (y)
226 The script will ask you for repository path, answer C:\\Kallithea\\Repos
226 The script will ask you for repository path, answer C:\\Kallithea\\Repos
227 (or similar)
227 (or similar)
228 The script will ask you for admin username and password, answer "admin"
228 The script will ask you for admin username and password, answer "admin"
229 + "123456" (or whatever you want)
229 + "123456" (or whatever you want)
230 The script will ask you for admin mail, answer "admin@xxxx.com" (or
230 The script will ask you for admin mail, answer "admin@xxxx.com" (or
231 whatever you want)
231 whatever you want)
232
232
233 If you make some mistake and the script does not end, don't worry, start
233 If you make some mistake and the script does not end, don't worry, start
234 it again.
234 it again.
235
235
236 Step 9 -- Running Kallithea
236 Step 9 -- Running Kallithea
237 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
237 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
238
238
239 In the previous command prompt, being in the C:\\Kallithea\\Bin folder,
239 In the previous command prompt, being in the C:\\Kallithea\\Bin folder,
240 just type::
240 just type::
241
241
242 paster serve production.ini
242 gearbox serve -c production.ini
243
243
244 Open yout web server, and go to http://127.0.0.1:5000
244 Open yout web server, and go to http://127.0.0.1:5000
245
245
246 It works!! :-)
246 It works!! :-)
247
247
248 Remark:
248 Remark:
249 If it does not work first time, just Ctrl-C the CMD process and start it
249 If it does not work first time, just Ctrl-C the CMD process and start it
250 again. Don't forget the "http://" in Internet Explorer
250 again. Don't forget the "http://" in Internet Explorer
251
251
252 What this Guide does not cover:
252 What this Guide does not cover:
253
253
254 - Installing Celery
254 - Installing Celery
255 - Running Kallithea as Windows Service. You can investigate here:
255 - Running Kallithea as Windows Service. You can investigate here:
256
256
257 - http://pypi.python.org/pypi/wsgisvc
257 - http://pypi.python.org/pypi/wsgisvc
258 - http://ryrobes.com/python/running-python-scripts-as-a-windows-service/
258 - http://ryrobes.com/python/running-python-scripts-as-a-windows-service/
259 - http://wiki.pylonshq.com/display/pylonscookbook/How+to+run+Pylons+as+a+Windows+service
259 - http://wiki.pylonshq.com/display/pylonscookbook/How+to+run+Pylons+as+a+Windows+service
260
260
261 - Using Apache. You can investigate here:
261 - Using Apache. You can investigate here:
262
262
263 - https://groups.google.com/group/rhodecode/msg/c433074e813ffdc4
263 - https://groups.google.com/group/rhodecode/msg/c433074e813ffdc4
@@ -1,140 +1,140 b''
1 .. _overview:
1 .. _overview:
2
2
3 =====================
3 =====================
4 Installation overview
4 Installation overview
5 =====================
5 =====================
6
6
7 Some overview and some details that can help understanding the options when
7 Some overview and some details that can help understanding the options when
8 installing Kallithea.
8 installing Kallithea.
9
9
10
10
11 Python environment
11 Python environment
12 ------------------
12 ------------------
13
13
14 **Kallithea** is written entirely in Python_ and requires Python version
14 **Kallithea** is written entirely in Python_ and requires Python version
15 2.6 or higher. Python 3.x is currently not supported.
15 2.6 or higher. Python 3.x is currently not supported.
16
16
17 Given a Python installation, there are different ways of providing the
17 Given a Python installation, there are different ways of providing the
18 environment for running Python applications. Each of them pretty much
18 environment for running Python applications. Each of them pretty much
19 corresponds to a ``site-packages`` directory somewhere where packages can be
19 corresponds to a ``site-packages`` directory somewhere where packages can be
20 installed.
20 installed.
21
21
22 Kallithea itself can be run from source or be installed, but even when running
22 Kallithea itself can be run from source or be installed, but even when running
23 from source, there are some dependencies that must be installed in the Python
23 from source, there are some dependencies that must be installed in the Python
24 environment used for running Kallithea.
24 environment used for running Kallithea.
25
25
26 - Packages *could* be installed in Python's ``site-packages`` directory ... but
26 - Packages *could* be installed in Python's ``site-packages`` directory ... but
27 that would require running pip_ as root and it would be hard to uninstall or
27 that would require running pip_ as root and it would be hard to uninstall or
28 upgrade and is probably not a good idea unless using a package manager.
28 upgrade and is probably not a good idea unless using a package manager.
29
29
30 - Packages could also be installed in ``~/.local`` ... but that is probably
30 - Packages could also be installed in ``~/.local`` ... but that is probably
31 only a good idea if using a dedicated user per application or instance.
31 only a good idea if using a dedicated user per application or instance.
32
32
33 - Finally, it can be installed in a virtualenv_. That is a very lightweight
33 - Finally, it can be installed in a virtualenv_. That is a very lightweight
34 "container" where each Kallithea instance can get its own dedicated and
34 "container" where each Kallithea instance can get its own dedicated and
35 self-contained virtual environment.
35 self-contained virtual environment.
36
36
37 We recommend using virtualenv for installing Kallithea.
37 We recommend using virtualenv for installing Kallithea.
38
38
39
39
40 Installation methods
40 Installation methods
41 --------------------
41 --------------------
42
42
43 Kallithea must be installed on a server. Kallithea is installed in a Python
43 Kallithea must be installed on a server. Kallithea is installed in a Python
44 environment so it can use packages that are installed there and make itself
44 environment so it can use packages that are installed there and make itself
45 available for other packages.
45 available for other packages.
46
46
47 Two different cases will pretty much cover the options for how it can be
47 Two different cases will pretty much cover the options for how it can be
48 installed.
48 installed.
49
49
50 - The Kallithea source repository can be cloned and used -- it is kept stable and
50 - The Kallithea source repository can be cloned and used -- it is kept stable and
51 can be used in production. The Kallithea maintainers use the development
51 can be used in production. The Kallithea maintainers use the development
52 branch in production. The advantage of installation from source and regularly
52 branch in production. The advantage of installation from source and regularly
53 updating it is that you take advantage of the most recent improvements. Using
53 updating it is that you take advantage of the most recent improvements. Using
54 it directly from a DVCS also means that it is easy to track local customizations.
54 it directly from a DVCS also means that it is easy to track local customizations.
55
55
56 Running ``pip install -e .`` in the source will use pip to install the
56 Running ``pip install -e .`` in the source will use pip to install the
57 necessary dependencies in the Python environment and create a
57 necessary dependencies in the Python environment and create a
58 ``.../site-packages/Kallithea.egg-link`` file there that points at the Kallithea
58 ``.../site-packages/Kallithea.egg-link`` file there that points at the Kallithea
59 source.
59 source.
60
60
61 - Kallithea can also be installed from ready-made packages using a package manager.
61 - Kallithea can also be installed from ready-made packages using a package manager.
62 The official released versions are available on PyPI_ and can be downloaded and
62 The official released versions are available on PyPI_ and can be downloaded and
63 installed with all dependencies using ``pip install kallithea``.
63 installed with all dependencies using ``pip install kallithea``.
64
64
65 With this method, Kallithea is installed in the Python environment as any
65 With this method, Kallithea is installed in the Python environment as any
66 other package, usually as a ``.../site-packages/Kallithea-X-py2.7.egg/``
66 other package, usually as a ``.../site-packages/Kallithea-X-py2.7.egg/``
67 directory with Python files and everything else that is needed.
67 directory with Python files and everything else that is needed.
68
68
69 (``pip install kallithea`` from a source tree will do pretty much the same
69 (``pip install kallithea`` from a source tree will do pretty much the same
70 but build the Kallithea package itself locally instead of downloading it.)
70 but build the Kallithea package itself locally instead of downloading it.)
71
71
72
72
73 Web server
73 Web server
74 ----------
74 ----------
75
75
76 Kallithea is (primarily) a WSGI_ application that must be run from a web
76 Kallithea is (primarily) a WSGI_ application that must be run from a web
77 server that serves WSGI applications over HTTP.
77 server that serves WSGI applications over HTTP.
78
78
79 Kallithea itself is not serving HTTP (or HTTPS); that is the web server's
79 Kallithea itself is not serving HTTP (or HTTPS); that is the web server's
80 responsibility. Kallithea does however need to know its own user facing URL
80 responsibility. Kallithea does however need to know its own user facing URL
81 (protocol, address, port and path) for each HTTP request. Kallithea will
81 (protocol, address, port and path) for each HTTP request. Kallithea will
82 usually use its own HTML/cookie based authentication but can also be configured
82 usually use its own HTML/cookie based authentication but can also be configured
83 to use web server authentication.
83 to use web server authentication.
84
84
85 There are several web server options:
85 There are several web server options:
86
86
87 - Kallithea uses the Paste_ tool as command line interface. Paste provides
87 - Kallithea uses the Gearbox_ tool as command line interface. Gearbox provides
88 ``paster serve`` as a convenient way to launch a Python WSGI / web server
88 ``gearbox serve`` as a convenient way to launch a Python WSGI / web server
89 from the command line. That is perfect for development and evaluation.
89 from the command line. That is perfect for development and evaluation.
90 Actual use in production might have different requirements and need extra
90 Actual use in production might have different requirements and need extra
91 work to make it manageable as a scalable system service.
91 work to make it manageable as a scalable system service.
92
92
93 Paste comes with its own built-in web server but Kallithea defaults to use
93 Gearbox comes with its own built-in web server but Kallithea defaults to use
94 Waitress_. Gunicorn_ is also an option. These web servers have different
94 Waitress_. Gunicorn_ is also an option. These web servers have different
95 limited feature sets.
95 limited feature sets.
96
96
97 The web server used by ``paster`` is configured in the ``.ini`` file passed
97 The web server used by ``gearbox`` is configured in the ``.ini`` file passed
98 to it. The entry point for the WSGI application is configured
98 to it. The entry point for the WSGI application is configured
99 in ``setup.py`` as ``kallithea.config.middleware:make_app``.
99 in ``setup.py`` as ``kallithea.config.middleware:make_app``.
100
100
101 - `Apache httpd`_ can serve WSGI applications directly using mod_wsgi_ and a
101 - `Apache httpd`_ can serve WSGI applications directly using mod_wsgi_ and a
102 simple Python file with the necessary configuration. This is a good option if
102 simple Python file with the necessary configuration. This is a good option if
103 Apache is an option.
103 Apache is an option.
104
104
105 - uWSGI_ is also a full web server with built-in WSGI module.
105 - uWSGI_ is also a full web server with built-in WSGI module.
106
106
107 - IIS_ can also server WSGI applications directly using isapi-wsgi_.
107 - IIS_ can also server WSGI applications directly using isapi-wsgi_.
108
108
109 - A `reverse HTTP proxy <https://en.wikipedia.org/wiki/Reverse_proxy>`_
109 - A `reverse HTTP proxy <https://en.wikipedia.org/wiki/Reverse_proxy>`_
110 can be put in front of another web server which has WSGI support.
110 can be put in front of another web server which has WSGI support.
111 Such a layered setup can be complex but might in some cases be the right
111 Such a layered setup can be complex but might in some cases be the right
112 option, for example to standardize on one internet-facing web server, to add
112 option, for example to standardize on one internet-facing web server, to add
113 encryption or special authentication or for other security reasons, to
113 encryption or special authentication or for other security reasons, to
114 provide caching of static files, or to provide load balancing or fail-over.
114 provide caching of static files, or to provide load balancing or fail-over.
115 Nginx_, Varnish_ and HAProxy_ are often used for this purpose, often in front
115 Nginx_, Varnish_ and HAProxy_ are often used for this purpose, often in front
116 of a ``paster`` server that somehow is wrapped as a service.
116 of a ``gearbox serve`` that somehow is wrapped as a service.
117
117
118 The best option depends on what you are familiar with and the requirements for
118 The best option depends on what you are familiar with and the requirements for
119 performance and stability. Also, keep in mind that Kallithea mainly is serving
119 performance and stability. Also, keep in mind that Kallithea mainly is serving
120 dynamically generated pages from a relatively slow Python process. Kallithea is
120 dynamically generated pages from a relatively slow Python process. Kallithea is
121 also often used inside organizations with a limited amount of users and thus no
121 also often used inside organizations with a limited amount of users and thus no
122 continuous hammering from the internet.
122 continuous hammering from the internet.
123
123
124
124
125 .. _Python: http://www.python.org/
125 .. _Python: http://www.python.org/
126 .. _Gunicorn: http://gunicorn.org/
126 .. _Gunicorn: http://gunicorn.org/
127 .. _Waitress: http://waitress.readthedocs.org/en/latest/
127 .. _Waitress: http://waitress.readthedocs.org/en/latest/
128 .. _virtualenv: http://pypi.python.org/pypi/virtualenv
128 .. _virtualenv: http://pypi.python.org/pypi/virtualenv
129 .. _Paste: http://pythonpaste.org/
129 .. _Gearbox: http://turbogears.readthedocs.io/en/latest/turbogears/gearbox.html
130 .. _PyPI: https://pypi.python.org/pypi
130 .. _PyPI: https://pypi.python.org/pypi
131 .. _Apache httpd: http://httpd.apache.org/
131 .. _Apache httpd: http://httpd.apache.org/
132 .. _mod_wsgi: https://code.google.com/p/modwsgi/
132 .. _mod_wsgi: https://code.google.com/p/modwsgi/
133 .. _isapi-wsgi: https://github.com/hexdump42/isapi-wsgi
133 .. _isapi-wsgi: https://github.com/hexdump42/isapi-wsgi
134 .. _uWSGI: https://uwsgi-docs.readthedocs.org/en/latest/
134 .. _uWSGI: https://uwsgi-docs.readthedocs.org/en/latest/
135 .. _nginx: http://nginx.org/en/
135 .. _nginx: http://nginx.org/en/
136 .. _iis: http://en.wikipedia.org/wiki/Internet_Information_Services
136 .. _iis: http://en.wikipedia.org/wiki/Internet_Information_Services
137 .. _pip: http://en.wikipedia.org/wiki/Pip_%28package_manager%29
137 .. _pip: http://en.wikipedia.org/wiki/Pip_%28package_manager%29
138 .. _WSGI: http://en.wikipedia.org/wiki/Web_Server_Gateway_Interface
138 .. _WSGI: http://en.wikipedia.org/wiki/Web_Server_Gateway_Interface
139 .. _HAProxy: http://www.haproxy.org/
139 .. _HAProxy: http://www.haproxy.org/
140 .. _Varnish: https://www.varnish-cache.org/
140 .. _Varnish: https://www.varnish-cache.org/
@@ -1,874 +1,877 b''
1 .. _setup:
1 .. _setup:
2
2
3 =====
3 =====
4 Setup
4 Setup
5 =====
5 =====
6
6
7
7
8 Setting up Kallithea
8 Setting up Kallithea
9 --------------------
9 --------------------
10
10
11 First, you will need to create a Kallithea configuration file. Run the
11 First, you will need to create a Kallithea configuration file. Run the
12 following command to do so::
12 following command to do so::
13
13
14 paster make-config Kallithea my.ini
14 TODO make-config Kallithea my.ini
15
15
16 This will create the file ``my.ini`` in the current directory. This
16 This will create the file ``my.ini`` in the current directory. This
17 configuration file contains the various settings for Kallithea, e.g.
17 configuration file contains the various settings for Kallithea, e.g.
18 proxy port, email settings, usage of static files, cache, Celery
18 proxy port, email settings, usage of static files, cache, Celery
19 settings, and logging.
19 settings, and logging.
20
20
21 Next, you need to create the databases used by Kallithea. It is recommended to
21 Next, you need to create the databases used by Kallithea. It is recommended to
22 use PostgreSQL or SQLite (default). If you choose a database other than the
22 use PostgreSQL or SQLite (default). If you choose a database other than the
23 default, ensure you properly adjust the database URL in your ``my.ini``
23 default, ensure you properly adjust the database URL in your ``my.ini``
24 configuration file to use this other database. Kallithea currently supports
24 configuration file to use this other database. Kallithea currently supports
25 PostgreSQL, SQLite and MySQL databases. Create the database by running
25 PostgreSQL, SQLite and MySQL databases. Create the database by running
26 the following command::
26 the following command::
27
27
28 paster setup-db my.ini
28 gearbox setup-db -c my.ini
29
29
30 This will prompt you for a "root" path. This "root" path is the location where
30 This will prompt you for a "root" path. This "root" path is the location where
31 Kallithea will store all of its repositories on the current machine. After
31 Kallithea will store all of its repositories on the current machine. After
32 entering this "root" path ``setup-db`` will also prompt you for a username
32 entering this "root" path ``setup-db`` will also prompt you for a username
33 and password for the initial admin account which ``setup-db`` sets
33 and password for the initial admin account which ``setup-db`` sets
34 up for you.
34 up for you.
35
35
36 The ``setup-db`` values can also be given on the command line.
36 The ``setup-db`` values can also be given on the command line.
37 Example::
37 Example::
38
38
39 paster setup-db my.ini --user=nn --password=secret --email=nn@example.com --repos=/srv/repos
39 gearbox setup-db -c my.ini --user=nn --password=secret --email=nn@example.com --repos=/srv/repos
40
40
41 The ``setup-db`` command will create all needed tables and an
41 The ``setup-db`` command will create all needed tables and an
42 admin account. When choosing a root path you can either use a new
42 admin account. When choosing a root path you can either use a new
43 empty location, or a location which already contains existing
43 empty location, or a location which already contains existing
44 repositories. If you choose a location which contains existing
44 repositories. If you choose a location which contains existing
45 repositories Kallithea will add all of the repositories at the chosen
45 repositories Kallithea will add all of the repositories at the chosen
46 location to its database. (Note: make sure you specify the correct
46 location to its database. (Note: make sure you specify the correct
47 path to the root).
47 path to the root).
48
48
49 .. note:: the given path for Mercurial_ repositories **must** be write
49 .. note:: the given path for Mercurial_ repositories **must** be write
50 accessible for the application. It's very important since
50 accessible for the application. It's very important since
51 the Kallithea web interface will work without write access,
51 the Kallithea web interface will work without write access,
52 but when trying to do a push it will fail with permission
52 but when trying to do a push it will fail with permission
53 denied errors unless it has write access.
53 denied errors unless it has write access.
54
54
55 You are now ready to use Kallithea. To run it simply execute::
55 You are now ready to use Kallithea. To run it simply execute::
56
56
57 paster serve my.ini
57 gearbox serve -c my.ini
58
58
59 - This command runs the Kallithea server. The web app should be available at
59 - This command runs the Kallithea server. The web app should be available at
60 http://127.0.0.1:5000. The IP address and port is configurable via the
60 http://127.0.0.1:5000. The IP address and port is configurable via the
61 configuration file created in the previous step.
61 configuration file created in the previous step.
62 - Log in to Kallithea using the admin account created when running ``setup-db``.
62 - Log in to Kallithea using the admin account created when running ``setup-db``.
63 - The default permissions on each repository is read, and the owner is admin.
63 - The default permissions on each repository is read, and the owner is admin.
64 Remember to update these if needed.
64 Remember to update these if needed.
65 - In the admin panel you can toggle LDAP, anonymous, and permissions
65 - In the admin panel you can toggle LDAP, anonymous, and permissions
66 settings, as well as edit more advanced options on users and
66 settings, as well as edit more advanced options on users and
67 repositories.
67 repositories.
68
68
69
69
70 Using Kallithea with SSH
70 Using Kallithea with SSH
71 ------------------------
71 ------------------------
72
72
73 Kallithea currently only hosts repositories using http and https. (The addition
73 Kallithea currently only hosts repositories using http and https. (The addition
74 of ssh hosting is a planned future feature.) However you can easily use ssh in
74 of ssh hosting is a planned future feature.) However you can easily use ssh in
75 parallel with Kallithea. (Repository access via ssh is a standard "out of
75 parallel with Kallithea. (Repository access via ssh is a standard "out of
76 the box" feature of Mercurial_ and you can use this to access any of the
76 the box" feature of Mercurial_ and you can use this to access any of the
77 repositories that Kallithea is hosting. See PublishingRepositories_)
77 repositories that Kallithea is hosting. See PublishingRepositories_)
78
78
79 Kallithea repository structures are kept in directories with the same name
79 Kallithea repository structures are kept in directories with the same name
80 as the project. When using repository groups, each group is a subdirectory.
80 as the project. When using repository groups, each group is a subdirectory.
81 This allows you to easily use ssh for accessing repositories.
81 This allows you to easily use ssh for accessing repositories.
82
82
83 In order to use ssh you need to make sure that your web server and the users'
83 In order to use ssh you need to make sure that your web server and the users'
84 login accounts have the correct permissions set on the appropriate directories.
84 login accounts have the correct permissions set on the appropriate directories.
85
85
86 .. note:: These permissions are independent of any permissions you
86 .. note:: These permissions are independent of any permissions you
87 have set up using the Kallithea web interface.
87 have set up using the Kallithea web interface.
88
88
89 If your main directory (the same as set in Kallithea settings) is for
89 If your main directory (the same as set in Kallithea settings) is for
90 example set to ``/srv/repos`` and the repository you are using is
90 example set to ``/srv/repos`` and the repository you are using is
91 named ``kallithea``, then to clone via ssh you should run::
91 named ``kallithea``, then to clone via ssh you should run::
92
92
93 hg clone ssh://user@kallithea.example.com/srv/repos/kallithea
93 hg clone ssh://user@kallithea.example.com/srv/repos/kallithea
94
94
95 Using other external tools such as mercurial-server_ or using ssh key-based
95 Using other external tools such as mercurial-server_ or using ssh key-based
96 authentication is fully supported.
96 authentication is fully supported.
97
97
98 .. note:: In an advanced setup, in order for your ssh access to use
98 .. note:: In an advanced setup, in order for your ssh access to use
99 the same permissions as set up via the Kallithea web
99 the same permissions as set up via the Kallithea web
100 interface, you can create an authentication hook to connect
100 interface, you can create an authentication hook to connect
101 to the Kallithea db and run check functions for permissions
101 to the Kallithea db and run check functions for permissions
102 against that.
102 against that.
103
103
104
104
105 Setting up Whoosh full text search
105 Setting up Whoosh full text search
106 ----------------------------------
106 ----------------------------------
107
107
108 Kallithea provides full text search of repositories using `Whoosh`__.
108 Kallithea provides full text search of repositories using `Whoosh`__.
109
109
110 .. __: https://pythonhosted.org/Whoosh/
110 .. __: https://pythonhosted.org/Whoosh/
111
111
112 For an incremental index build, run::
112 For an incremental index build, run::
113
113
114 paster make-index my.ini
114 gearbox make-index -c my.ini
115
115
116 For a full index rebuild, run::
116 For a full index rebuild, run::
117
117
118 paster make-index my.ini -f
118 gearbox make-index -c my.ini -f
119
119
120 The ``--repo-location`` option allows the location of the repositories to be overridden;
120 The ``--repo-location`` option allows the location of the repositories to be overridden;
121 usually, the location is retrieved from the Kallithea database.
121 usually, the location is retrieved from the Kallithea database.
122
122
123 The ``--index-only`` option can be used to limit the indexed repositories to a comma-separated list::
123 The ``--index-only`` option can be used to limit the indexed repositories to a comma-separated list::
124
124
125 paster make-index my.ini --index-only=vcs,kallithea
125 gearbox make-index -c my.ini --index-only=vcs,kallithea
126
126
127 To keep your index up-to-date it is necessary to do periodic index builds;
127 To keep your index up-to-date it is necessary to do periodic index builds;
128 for this, it is recommended to use a crontab entry. Example::
128 for this, it is recommended to use a crontab entry. Example::
129
129
130 0 3 * * * /path/to/virtualenv/bin/paster make-index /path/to/kallithea/my.ini
130 0 3 * * * /path/to/virtualenv/bin/gearbox make-index -c /path/to/kallithea/my.ini
131
131
132 When using incremental mode (the default), Whoosh will check the last
132 When using incremental mode (the default), Whoosh will check the last
133 modification date of each file and add it to be reindexed if a newer file is
133 modification date of each file and add it to be reindexed if a newer file is
134 available. The indexing daemon checks for any removed files and removes them
134 available. The indexing daemon checks for any removed files and removes them
135 from index.
135 from index.
136
136
137 If you want to rebuild the index from scratch, you can use the ``-f`` flag as above,
137 If you want to rebuild the index from scratch, you can use the ``-f`` flag as above,
138 or in the admin panel you can check the "build from scratch" checkbox.
138 or in the admin panel you can check the "build from scratch" checkbox.
139
139
140 .. _ldap-setup:
140 .. _ldap-setup:
141
141
142
142
143 Setting up LDAP support
143 Setting up LDAP support
144 -----------------------
144 -----------------------
145
145
146 Kallithea supports LDAP authentication. In order
146 Kallithea supports LDAP authentication. In order
147 to use LDAP, you have to install the python-ldap_ package. This package is
147 to use LDAP, you have to install the python-ldap_ package. This package is
148 available via PyPI, so you can install it by running::
148 available via PyPI, so you can install it by running::
149
149
150 pip install python-ldap
150 pip install python-ldap
151
151
152 .. note:: ``python-ldap`` requires some libraries to be installed on
152 .. note:: ``python-ldap`` requires some libraries to be installed on
153 your system, so before installing it check that you have at
153 your system, so before installing it check that you have at
154 least the ``openldap`` and ``sasl`` libraries.
154 least the ``openldap`` and ``sasl`` libraries.
155
155
156 Choose *Admin > Authentication*, click the ``kallithea.lib.auth_modules.auth_ldap`` button
156 Choose *Admin > Authentication*, click the ``kallithea.lib.auth_modules.auth_ldap`` button
157 and then *Save*, to enable the LDAP plugin and configure its settings.
157 and then *Save*, to enable the LDAP plugin and configure its settings.
158
158
159 Here's a typical LDAP setup::
159 Here's a typical LDAP setup::
160
160
161 Connection settings
161 Connection settings
162 Enable LDAP = checked
162 Enable LDAP = checked
163 Host = host.example.com
163 Host = host.example.com
164 Account = <account>
164 Account = <account>
165 Password = <password>
165 Password = <password>
166 Connection Security = LDAPS
166 Connection Security = LDAPS
167 Certificate Checks = DEMAND
167 Certificate Checks = DEMAND
168
168
169 Search settings
169 Search settings
170 Base DN = CN=users,DC=host,DC=example,DC=org
170 Base DN = CN=users,DC=host,DC=example,DC=org
171 LDAP Filter = (&(objectClass=user)(!(objectClass=computer)))
171 LDAP Filter = (&(objectClass=user)(!(objectClass=computer)))
172 LDAP Search Scope = SUBTREE
172 LDAP Search Scope = SUBTREE
173
173
174 Attribute mappings
174 Attribute mappings
175 Login Attribute = uid
175 Login Attribute = uid
176 First Name Attribute = firstName
176 First Name Attribute = firstName
177 Last Name Attribute = lastName
177 Last Name Attribute = lastName
178 Email Attribute = mail
178 Email Attribute = mail
179
179
180 If your user groups are placed in an Organisation Unit (OU) structure, the Search Settings configuration differs::
180 If your user groups are placed in an Organisation Unit (OU) structure, the Search Settings configuration differs::
181
181
182 Search settings
182 Search settings
183 Base DN = DC=host,DC=example,DC=org
183 Base DN = DC=host,DC=example,DC=org
184 LDAP Filter = (&(memberOf=CN=your user group,OU=subunit,OU=unit,DC=host,DC=example,DC=org)(objectClass=user))
184 LDAP Filter = (&(memberOf=CN=your user group,OU=subunit,OU=unit,DC=host,DC=example,DC=org)(objectClass=user))
185 LDAP Search Scope = SUBTREE
185 LDAP Search Scope = SUBTREE
186
186
187 .. _enable_ldap:
187 .. _enable_ldap:
188
188
189 Enable LDAP : required
189 Enable LDAP : required
190 Whether to use LDAP for authenticating users.
190 Whether to use LDAP for authenticating users.
191
191
192 .. _ldap_host:
192 .. _ldap_host:
193
193
194 Host : required
194 Host : required
195 LDAP server hostname or IP address. Can be also a comma separated
195 LDAP server hostname or IP address. Can be also a comma separated
196 list of servers to support LDAP fail-over.
196 list of servers to support LDAP fail-over.
197
197
198 .. _Port:
198 .. _Port:
199
199
200 Port : optional
200 Port : optional
201 Defaults to 389 for PLAIN un-encrypted LDAP and START_TLS.
201 Defaults to 389 for PLAIN un-encrypted LDAP and START_TLS.
202 Defaults to 636 for LDAPS.
202 Defaults to 636 for LDAPS.
203
203
204 .. _ldap_account:
204 .. _ldap_account:
205
205
206 Account : optional
206 Account : optional
207 Only required if the LDAP server does not allow anonymous browsing of
207 Only required if the LDAP server does not allow anonymous browsing of
208 records. This should be a special account for record browsing. This
208 records. This should be a special account for record browsing. This
209 will require `LDAP Password`_ below.
209 will require `LDAP Password`_ below.
210
210
211 .. _LDAP Password:
211 .. _LDAP Password:
212
212
213 Password : optional
213 Password : optional
214 Only required if the LDAP server does not allow anonymous browsing of
214 Only required if the LDAP server does not allow anonymous browsing of
215 records.
215 records.
216
216
217 .. _Enable LDAPS:
217 .. _Enable LDAPS:
218
218
219 Connection Security : required
219 Connection Security : required
220 Defines the connection to LDAP server
220 Defines the connection to LDAP server
221
221
222 PLAIN
222 PLAIN
223 Plain unencrypted LDAP connection.
223 Plain unencrypted LDAP connection.
224 This will by default use `Port`_ 389.
224 This will by default use `Port`_ 389.
225
225
226 LDAPS
226 LDAPS
227 Use secure LDAPS connections according to `Certificate
227 Use secure LDAPS connections according to `Certificate
228 Checks`_ configuration.
228 Checks`_ configuration.
229 This will by default use `Port`_ 636.
229 This will by default use `Port`_ 636.
230
230
231 START_TLS
231 START_TLS
232 Use START TLS according to `Certificate Checks`_ configuration on an
232 Use START TLS according to `Certificate Checks`_ configuration on an
233 apparently "plain" LDAP connection.
233 apparently "plain" LDAP connection.
234 This will by default use `Port`_ 389.
234 This will by default use `Port`_ 389.
235
235
236 .. _Certificate Checks:
236 .. _Certificate Checks:
237
237
238 Certificate Checks : optional
238 Certificate Checks : optional
239 How SSL certificates verification is handled -- this is only useful when
239 How SSL certificates verification is handled -- this is only useful when
240 `Enable LDAPS`_ is enabled. Only DEMAND or HARD offer full SSL security
240 `Enable LDAPS`_ is enabled. Only DEMAND or HARD offer full SSL security
241 with mandatory certificate validation, while the other options are
241 with mandatory certificate validation, while the other options are
242 susceptible to man-in-the-middle attacks.
242 susceptible to man-in-the-middle attacks.
243
243
244 NEVER
244 NEVER
245 A serve certificate will never be requested or checked.
245 A serve certificate will never be requested or checked.
246
246
247 ALLOW
247 ALLOW
248 A server certificate is requested. Failure to provide a
248 A server certificate is requested. Failure to provide a
249 certificate or providing a bad certificate will not terminate the
249 certificate or providing a bad certificate will not terminate the
250 session.
250 session.
251
251
252 TRY
252 TRY
253 A server certificate is requested. Failure to provide a
253 A server certificate is requested. Failure to provide a
254 certificate does not halt the session; providing a bad certificate
254 certificate does not halt the session; providing a bad certificate
255 halts the session.
255 halts the session.
256
256
257 DEMAND
257 DEMAND
258 A server certificate is requested and must be provided and
258 A server certificate is requested and must be provided and
259 authenticated for the session to proceed.
259 authenticated for the session to proceed.
260
260
261 HARD
261 HARD
262 The same as DEMAND.
262 The same as DEMAND.
263
263
264 .. _Custom CA Certificates:
264 .. _Custom CA Certificates:
265
265
266 Custom CA Certificates : optional
266 Custom CA Certificates : optional
267 Directory used by OpenSSL to find CAs for validating the LDAP server certificate.
267 Directory used by OpenSSL to find CAs for validating the LDAP server certificate.
268 Python 2.7.10 and later default to using the system certificate store, and
268 Python 2.7.10 and later default to using the system certificate store, and
269 this should thus not be necessary when using certificates signed by a CA
269 this should thus not be necessary when using certificates signed by a CA
270 trusted by the system.
270 trusted by the system.
271 It can be set to something like `/etc/openldap/cacerts` on older systems or
271 It can be set to something like `/etc/openldap/cacerts` on older systems or
272 if using self-signed certificates.
272 if using self-signed certificates.
273
273
274 .. _Base DN:
274 .. _Base DN:
275
275
276 Base DN : required
276 Base DN : required
277 The Distinguished Name (DN) where searches for users will be performed.
277 The Distinguished Name (DN) where searches for users will be performed.
278 Searches can be controlled by `LDAP Filter`_ and `LDAP Search Scope`_.
278 Searches can be controlled by `LDAP Filter`_ and `LDAP Search Scope`_.
279
279
280 .. _LDAP Filter:
280 .. _LDAP Filter:
281
281
282 LDAP Filter : optional
282 LDAP Filter : optional
283 A LDAP filter defined by RFC 2254. This is more useful when `LDAP
283 A LDAP filter defined by RFC 2254. This is more useful when `LDAP
284 Search Scope`_ is set to SUBTREE. The filter is useful for limiting
284 Search Scope`_ is set to SUBTREE. The filter is useful for limiting
285 which LDAP objects are identified as representing Users for
285 which LDAP objects are identified as representing Users for
286 authentication. The filter is augmented by `Login Attribute`_ below.
286 authentication. The filter is augmented by `Login Attribute`_ below.
287 This can commonly be left blank.
287 This can commonly be left blank.
288
288
289 .. _LDAP Search Scope:
289 .. _LDAP Search Scope:
290
290
291 LDAP Search Scope : required
291 LDAP Search Scope : required
292 This limits how far LDAP will search for a matching object.
292 This limits how far LDAP will search for a matching object.
293
293
294 BASE
294 BASE
295 Only allows searching of `Base DN`_ and is usually not what you
295 Only allows searching of `Base DN`_ and is usually not what you
296 want.
296 want.
297
297
298 ONELEVEL
298 ONELEVEL
299 Searches all entries under `Base DN`_, but not Base DN itself.
299 Searches all entries under `Base DN`_, but not Base DN itself.
300
300
301 SUBTREE
301 SUBTREE
302 Searches all entries below `Base DN`_, but not Base DN itself.
302 Searches all entries below `Base DN`_, but not Base DN itself.
303 When using SUBTREE `LDAP Filter`_ is useful to limit object
303 When using SUBTREE `LDAP Filter`_ is useful to limit object
304 location.
304 location.
305
305
306 .. _Login Attribute:
306 .. _Login Attribute:
307
307
308 Login Attribute : required
308 Login Attribute : required
309 The LDAP record attribute that will be matched as the USERNAME or
309 The LDAP record attribute that will be matched as the USERNAME or
310 ACCOUNT used to connect to Kallithea. This will be added to `LDAP
310 ACCOUNT used to connect to Kallithea. This will be added to `LDAP
311 Filter`_ for locating the User object. If `LDAP Filter`_ is specified as
311 Filter`_ for locating the User object. If `LDAP Filter`_ is specified as
312 "LDAPFILTER", `Login Attribute`_ is specified as "uid" and the user has
312 "LDAPFILTER", `Login Attribute`_ is specified as "uid" and the user has
313 connected as "jsmith" then the `LDAP Filter`_ will be augmented as below
313 connected as "jsmith" then the `LDAP Filter`_ will be augmented as below
314 ::
314 ::
315
315
316 (&(LDAPFILTER)(uid=jsmith))
316 (&(LDAPFILTER)(uid=jsmith))
317
317
318 .. _ldap_attr_firstname:
318 .. _ldap_attr_firstname:
319
319
320 First Name Attribute : required
320 First Name Attribute : required
321 The LDAP record attribute which represents the user's first name.
321 The LDAP record attribute which represents the user's first name.
322
322
323 .. _ldap_attr_lastname:
323 .. _ldap_attr_lastname:
324
324
325 Last Name Attribute : required
325 Last Name Attribute : required
326 The LDAP record attribute which represents the user's last name.
326 The LDAP record attribute which represents the user's last name.
327
327
328 .. _ldap_attr_email:
328 .. _ldap_attr_email:
329
329
330 Email Attribute : required
330 Email Attribute : required
331 The LDAP record attribute which represents the user's email address.
331 The LDAP record attribute which represents the user's email address.
332
332
333 If all data are entered correctly, and python-ldap_ is properly installed
333 If all data are entered correctly, and python-ldap_ is properly installed
334 users should be granted access to Kallithea with LDAP accounts. At this
334 users should be granted access to Kallithea with LDAP accounts. At this
335 time user information is copied from LDAP into the Kallithea user database.
335 time user information is copied from LDAP into the Kallithea user database.
336 This means that updates of an LDAP user object may not be reflected as a
336 This means that updates of an LDAP user object may not be reflected as a
337 user update in Kallithea.
337 user update in Kallithea.
338
338
339 If You have problems with LDAP access and believe You entered correct
339 If You have problems with LDAP access and believe You entered correct
340 information check out the Kallithea logs, any error messages sent from LDAP
340 information check out the Kallithea logs, any error messages sent from LDAP
341 will be saved there.
341 will be saved there.
342
342
343 Active Directory
343 Active Directory
344 ^^^^^^^^^^^^^^^^
344 ^^^^^^^^^^^^^^^^
345
345
346 Kallithea can use Microsoft Active Directory for user authentication. This
346 Kallithea can use Microsoft Active Directory for user authentication. This
347 is done through an LDAP or LDAPS connection to Active Directory. The
347 is done through an LDAP or LDAPS connection to Active Directory. The
348 following LDAP configuration settings are typical for using Active
348 following LDAP configuration settings are typical for using Active
349 Directory ::
349 Directory ::
350
350
351 Base DN = OU=SBSUsers,OU=Users,OU=MyBusiness,DC=v3sys,DC=local
351 Base DN = OU=SBSUsers,OU=Users,OU=MyBusiness,DC=v3sys,DC=local
352 Login Attribute = sAMAccountName
352 Login Attribute = sAMAccountName
353 First Name Attribute = givenName
353 First Name Attribute = givenName
354 Last Name Attribute = sn
354 Last Name Attribute = sn
355 Email Attribute = mail
355 Email Attribute = mail
356
356
357 All other LDAP settings will likely be site-specific and should be
357 All other LDAP settings will likely be site-specific and should be
358 appropriately configured.
358 appropriately configured.
359
359
360
360
361 Authentication by container or reverse-proxy
361 Authentication by container or reverse-proxy
362 --------------------------------------------
362 --------------------------------------------
363
363
364 Kallithea supports delegating the authentication
364 Kallithea supports delegating the authentication
365 of users to its WSGI container, or to a reverse-proxy server through which all
365 of users to its WSGI container, or to a reverse-proxy server through which all
366 clients access the application.
366 clients access the application.
367
367
368 When these authentication methods are enabled in Kallithea, it uses the
368 When these authentication methods are enabled in Kallithea, it uses the
369 username that the container/proxy (Apache or Nginx, etc.) provides and doesn't
369 username that the container/proxy (Apache or Nginx, etc.) provides and doesn't
370 perform the authentication itself. The authorization, however, is still done by
370 perform the authentication itself. The authorization, however, is still done by
371 Kallithea according to its settings.
371 Kallithea according to its settings.
372
372
373 When a user logs in for the first time using these authentication methods,
373 When a user logs in for the first time using these authentication methods,
374 a matching user account is created in Kallithea with default permissions. An
374 a matching user account is created in Kallithea with default permissions. An
375 administrator can then modify it using Kallithea's admin interface.
375 administrator can then modify it using Kallithea's admin interface.
376
376
377 It's also possible for an administrator to create accounts and configure their
377 It's also possible for an administrator to create accounts and configure their
378 permissions before the user logs in for the first time, using the :ref:`create-user` API.
378 permissions before the user logs in for the first time, using the :ref:`create-user` API.
379
379
380 Container-based authentication
380 Container-based authentication
381 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
381 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
382
382
383 In a container-based authentication setup, Kallithea reads the user name from
383 In a container-based authentication setup, Kallithea reads the user name from
384 the ``REMOTE_USER`` server variable provided by the WSGI container.
384 the ``REMOTE_USER`` server variable provided by the WSGI container.
385
385
386 After setting up your container (see `Apache with mod_wsgi`_), you'll need
386 After setting up your container (see `Apache with mod_wsgi`_), you'll need
387 to configure it to require authentication on the location configured for
387 to configure it to require authentication on the location configured for
388 Kallithea.
388 Kallithea.
389
389
390 Proxy pass-through authentication
390 Proxy pass-through authentication
391 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
391 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
392
392
393 In a proxy pass-through authentication setup, Kallithea reads the user name
393 In a proxy pass-through authentication setup, Kallithea reads the user name
394 from the ``X-Forwarded-User`` request header, which should be configured to be
394 from the ``X-Forwarded-User`` request header, which should be configured to be
395 sent by the reverse-proxy server.
395 sent by the reverse-proxy server.
396
396
397 After setting up your proxy solution (see `Apache virtual host reverse proxy example`_,
397 After setting up your proxy solution (see `Apache virtual host reverse proxy example`_,
398 `Apache as subdirectory`_ or `Nginx virtual host example`_), you'll need to
398 `Apache as subdirectory`_ or `Nginx virtual host example`_), you'll need to
399 configure the authentication and add the username in a request header named
399 configure the authentication and add the username in a request header named
400 ``X-Forwarded-User``.
400 ``X-Forwarded-User``.
401
401
402 For example, the following config section for Apache sets a subdirectory in a
402 For example, the following config section for Apache sets a subdirectory in a
403 reverse-proxy setup with basic auth:
403 reverse-proxy setup with basic auth:
404
404
405 .. code-block:: apache
405 .. code-block:: apache
406
406
407 <Location /someprefix>
407 <Location /someprefix>
408 ProxyPass http://127.0.0.1:5000/someprefix
408 ProxyPass http://127.0.0.1:5000/someprefix
409 ProxyPassReverse http://127.0.0.1:5000/someprefix
409 ProxyPassReverse http://127.0.0.1:5000/someprefix
410 SetEnvIf X-Url-Scheme https HTTPS=1
410 SetEnvIf X-Url-Scheme https HTTPS=1
411
411
412 AuthType Basic
412 AuthType Basic
413 AuthName "Kallithea authentication"
413 AuthName "Kallithea authentication"
414 AuthUserFile /srv/kallithea/.htpasswd
414 AuthUserFile /srv/kallithea/.htpasswd
415 Require valid-user
415 Require valid-user
416
416
417 RequestHeader unset X-Forwarded-User
417 RequestHeader unset X-Forwarded-User
418
418
419 RewriteEngine On
419 RewriteEngine On
420 RewriteCond %{LA-U:REMOTE_USER} (.+)
420 RewriteCond %{LA-U:REMOTE_USER} (.+)
421 RewriteRule .* - [E=RU:%1]
421 RewriteRule .* - [E=RU:%1]
422 RequestHeader set X-Forwarded-User %{RU}e
422 RequestHeader set X-Forwarded-User %{RU}e
423 </Location>
423 </Location>
424
424
425 Setting metadata in container/reverse-proxy
425 Setting metadata in container/reverse-proxy
426 """""""""""""""""""""""""""""""""""""""""""
426 """""""""""""""""""""""""""""""""""""""""""
427 When a new user account is created on the first login, Kallithea has no information about
427 When a new user account is created on the first login, Kallithea has no information about
428 the user's email and full name. So you can set some additional request headers like in the
428 the user's email and full name. So you can set some additional request headers like in the
429 example below. In this example the user is authenticated via Kerberos and an Apache
429 example below. In this example the user is authenticated via Kerberos and an Apache
430 mod_python fixup handler is used to get the user information from a LDAP server. But you
430 mod_python fixup handler is used to get the user information from a LDAP server. But you
431 could set the request headers however you want.
431 could set the request headers however you want.
432
432
433 .. code-block:: apache
433 .. code-block:: apache
434
434
435 <Location /someprefix>
435 <Location /someprefix>
436 ProxyPass http://127.0.0.1:5000/someprefix
436 ProxyPass http://127.0.0.1:5000/someprefix
437 ProxyPassReverse http://127.0.0.1:5000/someprefix
437 ProxyPassReverse http://127.0.0.1:5000/someprefix
438 SetEnvIf X-Url-Scheme https HTTPS=1
438 SetEnvIf X-Url-Scheme https HTTPS=1
439
439
440 AuthName "Kerberos Login"
440 AuthName "Kerberos Login"
441 AuthType Kerberos
441 AuthType Kerberos
442 Krb5Keytab /etc/apache2/http.keytab
442 Krb5Keytab /etc/apache2/http.keytab
443 KrbMethodK5Passwd off
443 KrbMethodK5Passwd off
444 KrbVerifyKDC on
444 KrbVerifyKDC on
445 Require valid-user
445 Require valid-user
446
446
447 PythonFixupHandler ldapmetadata
447 PythonFixupHandler ldapmetadata
448
448
449 RequestHeader set X_REMOTE_USER %{X_REMOTE_USER}e
449 RequestHeader set X_REMOTE_USER %{X_REMOTE_USER}e
450 RequestHeader set X_REMOTE_EMAIL %{X_REMOTE_EMAIL}e
450 RequestHeader set X_REMOTE_EMAIL %{X_REMOTE_EMAIL}e
451 RequestHeader set X_REMOTE_FIRSTNAME %{X_REMOTE_FIRSTNAME}e
451 RequestHeader set X_REMOTE_FIRSTNAME %{X_REMOTE_FIRSTNAME}e
452 RequestHeader set X_REMOTE_LASTNAME %{X_REMOTE_LASTNAME}e
452 RequestHeader set X_REMOTE_LASTNAME %{X_REMOTE_LASTNAME}e
453 </Location>
453 </Location>
454
454
455 .. code-block:: python
455 .. code-block:: python
456
456
457 from mod_python import apache
457 from mod_python import apache
458 import ldap
458 import ldap
459
459
460 LDAP_SERVER = "ldaps://server.mydomain.com:636"
460 LDAP_SERVER = "ldaps://server.mydomain.com:636"
461 LDAP_USER = ""
461 LDAP_USER = ""
462 LDAP_PASS = ""
462 LDAP_PASS = ""
463 LDAP_ROOT = "dc=mydomain,dc=com"
463 LDAP_ROOT = "dc=mydomain,dc=com"
464 LDAP_FILTER = "sAMAccountName=%s"
464 LDAP_FILTER = "sAMAccountName=%s"
465 LDAP_ATTR_LIST = ['sAMAccountName','givenname','sn','mail']
465 LDAP_ATTR_LIST = ['sAMAccountName','givenname','sn','mail']
466
466
467 def fixuphandler(req):
467 def fixuphandler(req):
468 if req.user is None:
468 if req.user is None:
469 # no user to search for
469 # no user to search for
470 return apache.OK
470 return apache.OK
471 else:
471 else:
472 try:
472 try:
473 if('\\' in req.user):
473 if('\\' in req.user):
474 username = req.user.split('\\')[1]
474 username = req.user.split('\\')[1]
475 elif('@' in req.user):
475 elif('@' in req.user):
476 username = req.user.split('@')[0]
476 username = req.user.split('@')[0]
477 else:
477 else:
478 username = req.user
478 username = req.user
479 l = ldap.initialize(LDAP_SERVER)
479 l = ldap.initialize(LDAP_SERVER)
480 l.simple_bind_s(LDAP_USER, LDAP_PASS)
480 l.simple_bind_s(LDAP_USER, LDAP_PASS)
481 r = l.search_s(LDAP_ROOT, ldap.SCOPE_SUBTREE, LDAP_FILTER % username, attrlist=LDAP_ATTR_LIST)
481 r = l.search_s(LDAP_ROOT, ldap.SCOPE_SUBTREE, LDAP_FILTER % username, attrlist=LDAP_ATTR_LIST)
482
482
483 req.subprocess_env['X_REMOTE_USER'] = username
483 req.subprocess_env['X_REMOTE_USER'] = username
484 req.subprocess_env['X_REMOTE_EMAIL'] = r[0][1]['mail'][0].lower()
484 req.subprocess_env['X_REMOTE_EMAIL'] = r[0][1]['mail'][0].lower()
485 req.subprocess_env['X_REMOTE_FIRSTNAME'] = "%s" % r[0][1]['givenname'][0]
485 req.subprocess_env['X_REMOTE_FIRSTNAME'] = "%s" % r[0][1]['givenname'][0]
486 req.subprocess_env['X_REMOTE_LASTNAME'] = "%s" % r[0][1]['sn'][0]
486 req.subprocess_env['X_REMOTE_LASTNAME'] = "%s" % r[0][1]['sn'][0]
487 except Exception, e:
487 except Exception, e:
488 apache.log_error("error getting data from ldap %s" % str(e), apache.APLOG_ERR)
488 apache.log_error("error getting data from ldap %s" % str(e), apache.APLOG_ERR)
489
489
490 return apache.OK
490 return apache.OK
491
491
492 .. note::
492 .. note::
493 If you enable proxy pass-through authentication, make sure your server is
493 If you enable proxy pass-through authentication, make sure your server is
494 only accessible through the proxy. Otherwise, any client would be able to
494 only accessible through the proxy. Otherwise, any client would be able to
495 forge the authentication header and could effectively become authenticated
495 forge the authentication header and could effectively become authenticated
496 using any account of their liking.
496 using any account of their liking.
497
497
498
498
499 Integration with issue trackers
499 Integration with issue trackers
500 -------------------------------
500 -------------------------------
501
501
502 Kallithea provides a simple integration with issue trackers. It's possible
502 Kallithea provides a simple integration with issue trackers. It's possible
503 to define a regular expression that will match an issue ID in commit messages,
503 to define a regular expression that will match an issue ID in commit messages,
504 and have that replaced with a URL to the issue. To enable this simply
504 and have that replaced with a URL to the issue. To enable this simply
505 uncomment the following variables in the ini file::
505 uncomment the following variables in the ini file::
506
506
507 issue_pat = (?:^#|\s#)(\w+)
507 issue_pat = (?:^#|\s#)(\w+)
508 issue_server_link = https://issues.example.com/{repo}/issue/{id}
508 issue_server_link = https://issues.example.com/{repo}/issue/{id}
509 issue_prefix = #
509 issue_prefix = #
510
510
511 ``issue_pat`` is the regular expression describing which strings in
511 ``issue_pat`` is the regular expression describing which strings in
512 commit messages will be treated as issue references. A match group in
512 commit messages will be treated as issue references. A match group in
513 parentheses should be used to specify the actual issue id.
513 parentheses should be used to specify the actual issue id.
514
514
515 The default expression matches issues in the format ``#<number>``, e.g., ``#300``.
515 The default expression matches issues in the format ``#<number>``, e.g., ``#300``.
516
516
517 Matched issue references are replaced with the link specified in
517 Matched issue references are replaced with the link specified in
518 ``issue_server_link``. ``{id}`` is replaced with the issue ID, and
518 ``issue_server_link``. ``{id}`` is replaced with the issue ID, and
519 ``{repo}`` with the repository name. Since the # is stripped away,
519 ``{repo}`` with the repository name. Since the # is stripped away,
520 ``issue_prefix`` is prepended to the link text. ``issue_prefix`` doesn't
520 ``issue_prefix`` is prepended to the link text. ``issue_prefix`` doesn't
521 necessarily need to be ``#``: if you set issue prefix to ``ISSUE-`` this will
521 necessarily need to be ``#``: if you set issue prefix to ``ISSUE-`` this will
522 generate a URL in the format:
522 generate a URL in the format:
523
523
524 .. code-block:: html
524 .. code-block:: html
525
525
526 <a href="https://issues.example.com/example_repo/issue/300">ISSUE-300</a>
526 <a href="https://issues.example.com/example_repo/issue/300">ISSUE-300</a>
527
527
528 If needed, more than one pattern can be specified by appending a unique suffix to
528 If needed, more than one pattern can be specified by appending a unique suffix to
529 the variables. For example::
529 the variables. For example::
530
530
531 issue_pat_wiki = (?:wiki-)(.+)
531 issue_pat_wiki = (?:wiki-)(.+)
532 issue_server_link_wiki = https://wiki.example.com/{id}
532 issue_server_link_wiki = https://wiki.example.com/{id}
533 issue_prefix_wiki = WIKI-
533 issue_prefix_wiki = WIKI-
534
534
535 With these settings, wiki pages can be referenced as wiki-some-id, and every
535 With these settings, wiki pages can be referenced as wiki-some-id, and every
536 such reference will be transformed into:
536 such reference will be transformed into:
537
537
538 .. code-block:: html
538 .. code-block:: html
539
539
540 <a href="https://wiki.example.com/some-id">WIKI-some-id</a>
540 <a href="https://wiki.example.com/some-id">WIKI-some-id</a>
541
541
542
542
543 Hook management
543 Hook management
544 ---------------
544 ---------------
545
545
546 Hooks can be managed in similar way to that used in ``.hgrc`` files.
546 Hooks can be managed in similar way to that used in ``.hgrc`` files.
547 To manage hooks, choose *Admin > Settings > Hooks*.
547 To manage hooks, choose *Admin > Settings > Hooks*.
548
548
549 The built-in hooks cannot be modified, though they can be enabled or disabled in the *VCS* section.
549 The built-in hooks cannot be modified, though they can be enabled or disabled in the *VCS* section.
550
550
551 To add another custom hook simply fill in the first textbox with
551 To add another custom hook simply fill in the first textbox with
552 ``<name>.<hook_type>`` and the second with the hook path. Example hooks
552 ``<name>.<hook_type>`` and the second with the hook path. Example hooks
553 can be found in ``kallithea.lib.hooks``.
553 can be found in ``kallithea.lib.hooks``.
554
554
555
555
556 Changing default encoding
556 Changing default encoding
557 -------------------------
557 -------------------------
558
558
559 By default, Kallithea uses UTF-8 encoding.
559 By default, Kallithea uses UTF-8 encoding.
560 This is configurable as ``default_encoding`` in the .ini file.
560 This is configurable as ``default_encoding`` in the .ini file.
561 This affects many parts in Kallithea including user names, filenames, and
561 This affects many parts in Kallithea including user names, filenames, and
562 encoding of commit messages. In addition Kallithea can detect if the ``chardet``
562 encoding of commit messages. In addition Kallithea can detect if the ``chardet``
563 library is installed. If ``chardet`` is detected Kallithea will fallback to it
563 library is installed. If ``chardet`` is detected Kallithea will fallback to it
564 when there are encode/decode errors.
564 when there are encode/decode errors.
565
565
566
566
567 Celery configuration
567 Celery configuration
568 --------------------
568 --------------------
569
569
570 Kallithea can use the distributed task queue system Celery_ to run tasks like
570 Kallithea can use the distributed task queue system Celery_ to run tasks like
571 cloning repositories or sending emails.
571 cloning repositories or sending emails.
572
572
573 Kallithea will in most setups work perfectly fine out of the box (without
573 Kallithea will in most setups work perfectly fine out of the box (without
574 Celery), executing all tasks in the web server process. Some tasks can however
574 Celery), executing all tasks in the web server process. Some tasks can however
575 take some time to run and it can be better to run such tasks asynchronously in
575 take some time to run and it can be better to run such tasks asynchronously in
576 a separate process so the web server can focus on serving web requests.
576 a separate process so the web server can focus on serving web requests.
577
577
578 For installation and configuration of Celery, see the `Celery documentation`_.
578 For installation and configuration of Celery, see the `Celery documentation`_.
579 Note that Celery requires a message broker service like RabbitMQ_ (recommended)
579 Note that Celery requires a message broker service like RabbitMQ_ (recommended)
580 or Redis_.
580 or Redis_.
581
581
582 The use of Celery is configured in the Kallithea ini configuration file.
582 The use of Celery is configured in the Kallithea ini configuration file.
583 To enable it, simply set::
583 To enable it, simply set::
584
584
585 use_celery = true
585 use_celery = true
586
586
587 and add or change the ``celery.*`` and ``broker.*`` configuration variables.
587 and add or change the ``celery.*`` and ``broker.*`` configuration variables.
588
588
589 Remember that the ini files use the format with '.' and not with '_' like
589 Remember that the ini files use the format with '.' and not with '_' like
590 Celery. So for example setting `BROKER_HOST` in Celery means setting
590 Celery. So for example setting `BROKER_HOST` in Celery means setting
591 `broker.host` in the configuration file.
591 `broker.host` in the configuration file.
592
592
593 To start the Celery process, run::
593 To start the Celery process, run::
594
594
595 paster celeryd <configfile.ini>
595 gearbox celeryd -c <configfile.ini>
596
597 Extra options to the Celery worker can be passed after ``--`` - see ``-- -h``
598 for more info.
596
599
597 .. note::
600 .. note::
598 Make sure you run this command from the same virtualenv, and with the same
601 Make sure you run this command from the same virtualenv, and with the same
599 user that Kallithea runs.
602 user that Kallithea runs.
600
603
601
604
602 HTTPS support
605 HTTPS support
603 -------------
606 -------------
604
607
605 Kallithea will by default generate URLs based on the WSGI environment.
608 Kallithea will by default generate URLs based on the WSGI environment.
606
609
607 Alternatively, you can use some special configuration settings to control
610 Alternatively, you can use some special configuration settings to control
608 directly which scheme/protocol Kallithea will use when generating URLs:
611 directly which scheme/protocol Kallithea will use when generating URLs:
609
612
610 - With ``https_fixup = true``, the scheme will be taken from the
613 - With ``https_fixup = true``, the scheme will be taken from the
611 ``X-Url-Scheme``, ``X-Forwarded-Scheme`` or ``X-Forwarded-Proto`` HTTP header
614 ``X-Url-Scheme``, ``X-Forwarded-Scheme`` or ``X-Forwarded-Proto`` HTTP header
612 (default ``http``).
615 (default ``http``).
613 - With ``force_https = true`` the default will be ``https``.
616 - With ``force_https = true`` the default will be ``https``.
614 - With ``use_htsts = true``, Kallithea will set ``Strict-Transport-Security`` when using https.
617 - With ``use_htsts = true``, Kallithea will set ``Strict-Transport-Security`` when using https.
615
618
616
619
617 Nginx virtual host example
620 Nginx virtual host example
618 --------------------------
621 --------------------------
619
622
620 Sample config for Nginx using proxy:
623 Sample config for Nginx using proxy:
621
624
622 .. code-block:: nginx
625 .. code-block:: nginx
623
626
624 upstream kallithea {
627 upstream kallithea {
625 server 127.0.0.1:5000;
628 server 127.0.0.1:5000;
626 # add more instances for load balancing
629 # add more instances for load balancing
627 #server 127.0.0.1:5001;
630 #server 127.0.0.1:5001;
628 #server 127.0.0.1:5002;
631 #server 127.0.0.1:5002;
629 }
632 }
630
633
631 ## gist alias
634 ## gist alias
632 server {
635 server {
633 listen 443;
636 listen 443;
634 server_name gist.example.com;
637 server_name gist.example.com;
635 access_log /var/log/nginx/gist.access.log;
638 access_log /var/log/nginx/gist.access.log;
636 error_log /var/log/nginx/gist.error.log;
639 error_log /var/log/nginx/gist.error.log;
637
640
638 ssl on;
641 ssl on;
639 ssl_certificate gist.your.kallithea.server.crt;
642 ssl_certificate gist.your.kallithea.server.crt;
640 ssl_certificate_key gist.your.kallithea.server.key;
643 ssl_certificate_key gist.your.kallithea.server.key;
641
644
642 ssl_session_timeout 5m;
645 ssl_session_timeout 5m;
643
646
644 ssl_protocols SSLv3 TLSv1;
647 ssl_protocols SSLv3 TLSv1;
645 ssl_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA:DES-CBC3-SHA:AES128-SHA:RC4-SHA:RC4-MD5;
648 ssl_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA:DES-CBC3-SHA:AES128-SHA:RC4-SHA:RC4-MD5;
646 ssl_prefer_server_ciphers on;
649 ssl_prefer_server_ciphers on;
647
650
648 rewrite ^/(.+)$ https://kallithea.example.com/_admin/gists/$1;
651 rewrite ^/(.+)$ https://kallithea.example.com/_admin/gists/$1;
649 rewrite (.*) https://kallithea.example.com/_admin/gists;
652 rewrite (.*) https://kallithea.example.com/_admin/gists;
650 }
653 }
651
654
652 server {
655 server {
653 listen 443;
656 listen 443;
654 server_name kallithea.example.com
657 server_name kallithea.example.com
655 access_log /var/log/nginx/kallithea.access.log;
658 access_log /var/log/nginx/kallithea.access.log;
656 error_log /var/log/nginx/kallithea.error.log;
659 error_log /var/log/nginx/kallithea.error.log;
657
660
658 ssl on;
661 ssl on;
659 ssl_certificate your.kallithea.server.crt;
662 ssl_certificate your.kallithea.server.crt;
660 ssl_certificate_key your.kallithea.server.key;
663 ssl_certificate_key your.kallithea.server.key;
661
664
662 ssl_session_timeout 5m;
665 ssl_session_timeout 5m;
663
666
664 ssl_protocols SSLv3 TLSv1;
667 ssl_protocols SSLv3 TLSv1;
665 ssl_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA:DES-CBC3-SHA:AES128-SHA:RC4-SHA:RC4-MD5;
668 ssl_ciphers DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:EDH-RSA-DES-CBC3-SHA:AES256-SHA:DES-CBC3-SHA:AES128-SHA:RC4-SHA:RC4-MD5;
666 ssl_prefer_server_ciphers on;
669 ssl_prefer_server_ciphers on;
667
670
668 ## uncomment root directive if you want to serve static files by nginx
671 ## uncomment root directive if you want to serve static files by nginx
669 ## requires static_files = false in .ini file
672 ## requires static_files = false in .ini file
670 #root /srv/kallithea/kallithea/kallithea/public;
673 #root /srv/kallithea/kallithea/kallithea/public;
671 include /etc/nginx/proxy.conf;
674 include /etc/nginx/proxy.conf;
672 location / {
675 location / {
673 try_files $uri @kallithea;
676 try_files $uri @kallithea;
674 }
677 }
675
678
676 location @kallithea {
679 location @kallithea {
677 proxy_pass http://127.0.0.1:5000;
680 proxy_pass http://127.0.0.1:5000;
678 }
681 }
679
682
680 }
683 }
681
684
682 Here's the proxy.conf. It's tuned so it will not timeout on long
685 Here's the proxy.conf. It's tuned so it will not timeout on long
683 pushes or large pushes::
686 pushes or large pushes::
684
687
685 proxy_redirect off;
688 proxy_redirect off;
686 proxy_set_header Host $host;
689 proxy_set_header Host $host;
687 ## needed for container auth
690 ## needed for container auth
688 #proxy_set_header REMOTE_USER $remote_user;
691 #proxy_set_header REMOTE_USER $remote_user;
689 #proxy_set_header X-Forwarded-User $remote_user;
692 #proxy_set_header X-Forwarded-User $remote_user;
690 proxy_set_header X-Url-Scheme $scheme;
693 proxy_set_header X-Url-Scheme $scheme;
691 proxy_set_header X-Host $http_host;
694 proxy_set_header X-Host $http_host;
692 proxy_set_header X-Real-IP $remote_addr;
695 proxy_set_header X-Real-IP $remote_addr;
693 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
696 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
694 proxy_set_header Proxy-host $proxy_host;
697 proxy_set_header Proxy-host $proxy_host;
695 proxy_buffering off;
698 proxy_buffering off;
696 proxy_connect_timeout 7200;
699 proxy_connect_timeout 7200;
697 proxy_send_timeout 7200;
700 proxy_send_timeout 7200;
698 proxy_read_timeout 7200;
701 proxy_read_timeout 7200;
699 proxy_buffers 8 32k;
702 proxy_buffers 8 32k;
700 client_max_body_size 1024m;
703 client_max_body_size 1024m;
701 client_body_buffer_size 128k;
704 client_body_buffer_size 128k;
702 large_client_header_buffers 8 64k;
705 large_client_header_buffers 8 64k;
703
706
704
707
705 Apache virtual host reverse proxy example
708 Apache virtual host reverse proxy example
706 -----------------------------------------
709 -----------------------------------------
707
710
708 Here is a sample configuration file for Apache using proxy:
711 Here is a sample configuration file for Apache using proxy:
709
712
710 .. code-block:: apache
713 .. code-block:: apache
711
714
712 <VirtualHost *:80>
715 <VirtualHost *:80>
713 ServerName kallithea.example.com
716 ServerName kallithea.example.com
714
717
715 <Proxy *>
718 <Proxy *>
716 # For Apache 2.4 and later:
719 # For Apache 2.4 and later:
717 Require all granted
720 Require all granted
718
721
719 # For Apache 2.2 and earlier, instead use:
722 # For Apache 2.2 and earlier, instead use:
720 # Order allow,deny
723 # Order allow,deny
721 # Allow from all
724 # Allow from all
722 </Proxy>
725 </Proxy>
723
726
724 #important !
727 #important !
725 #Directive to properly generate url (clone url) for Kallithea
728 #Directive to properly generate url (clone url) for Kallithea
726 ProxyPreserveHost On
729 ProxyPreserveHost On
727
730
728 #kallithea instance
731 #kallithea instance
729 ProxyPass / http://127.0.0.1:5000/
732 ProxyPass / http://127.0.0.1:5000/
730 ProxyPassReverse / http://127.0.0.1:5000/
733 ProxyPassReverse / http://127.0.0.1:5000/
731
734
732 #to enable https use line below
735 #to enable https use line below
733 #SetEnvIf X-Url-Scheme https HTTPS=1
736 #SetEnvIf X-Url-Scheme https HTTPS=1
734 </VirtualHost>
737 </VirtualHost>
735
738
736 Additional tutorial
739 Additional tutorial
737 http://pylonsbook.com/en/1.1/deployment.html#using-apache-to-proxy-requests-to-pylons
740 http://pylonsbook.com/en/1.1/deployment.html#using-apache-to-proxy-requests-to-pylons
738
741
739
742
740 Apache as subdirectory
743 Apache as subdirectory
741 ----------------------
744 ----------------------
742
745
743 Apache subdirectory part:
746 Apache subdirectory part:
744
747
745 .. code-block:: apache
748 .. code-block:: apache
746
749
747 <Location /<someprefix> >
750 <Location /<someprefix> >
748 ProxyPass http://127.0.0.1:5000/<someprefix>
751 ProxyPass http://127.0.0.1:5000/<someprefix>
749 ProxyPassReverse http://127.0.0.1:5000/<someprefix>
752 ProxyPassReverse http://127.0.0.1:5000/<someprefix>
750 SetEnvIf X-Url-Scheme https HTTPS=1
753 SetEnvIf X-Url-Scheme https HTTPS=1
751 </Location>
754 </Location>
752
755
753 Besides the regular apache setup you will need to add the following line
756 Besides the regular apache setup you will need to add the following line
754 into ``[app:main]`` section of your .ini file::
757 into ``[app:main]`` section of your .ini file::
755
758
756 filter-with = proxy-prefix
759 filter-with = proxy-prefix
757
760
758 Add the following at the end of the .ini file::
761 Add the following at the end of the .ini file::
759
762
760 [filter:proxy-prefix]
763 [filter:proxy-prefix]
761 use = egg:PasteDeploy#prefix
764 use = egg:PasteDeploy#prefix
762 prefix = /<someprefix>
765 prefix = /<someprefix>
763
766
764 then change ``<someprefix>`` into your chosen prefix
767 then change ``<someprefix>`` into your chosen prefix
765
768
766
769
767 Apache with mod_wsgi
770 Apache with mod_wsgi
768 --------------------
771 --------------------
769
772
770 Alternatively, Kallithea can be set up with Apache under mod_wsgi. For
773 Alternatively, Kallithea can be set up with Apache under mod_wsgi. For
771 that, you'll need to:
774 that, you'll need to:
772
775
773 - Install mod_wsgi. If using a Debian-based distro, you can install
776 - Install mod_wsgi. If using a Debian-based distro, you can install
774 the package libapache2-mod-wsgi::
777 the package libapache2-mod-wsgi::
775
778
776 aptitude install libapache2-mod-wsgi
779 aptitude install libapache2-mod-wsgi
777
780
778 - Enable mod_wsgi::
781 - Enable mod_wsgi::
779
782
780 a2enmod wsgi
783 a2enmod wsgi
781
784
782 - Add global Apache configuration to tell mod_wsgi that Python only will be
785 - Add global Apache configuration to tell mod_wsgi that Python only will be
783 used in the WSGI processes and shouldn't be initialized in the Apache
786 used in the WSGI processes and shouldn't be initialized in the Apache
784 processes::
787 processes::
785
788
786 WSGIRestrictEmbedded On
789 WSGIRestrictEmbedded On
787
790
788 - Create a wsgi dispatch script, like the one below. Make sure you
791 - Create a wsgi dispatch script, like the one below. Make sure you
789 check that the paths correctly point to where you installed Kallithea
792 check that the paths correctly point to where you installed Kallithea
790 and its Python Virtual Environment.
793 and its Python Virtual Environment.
791 - Enable the ``WSGIScriptAlias`` directive for the WSGI dispatch script,
794 - Enable the ``WSGIScriptAlias`` directive for the WSGI dispatch script,
792 as in the following example. Once again, check the paths are
795 as in the following example. Once again, check the paths are
793 correctly specified.
796 correctly specified.
794
797
795 Here is a sample excerpt from an Apache Virtual Host configuration file:
798 Here is a sample excerpt from an Apache Virtual Host configuration file:
796
799
797 .. code-block:: apache
800 .. code-block:: apache
798
801
799 WSGIDaemonProcess kallithea processes=5 threads=1 maximum-requests=100 \
802 WSGIDaemonProcess kallithea processes=5 threads=1 maximum-requests=100 \
800 python-home=/srv/kallithea/venv
803 python-home=/srv/kallithea/venv
801 WSGIProcessGroup kallithea
804 WSGIProcessGroup kallithea
802 WSGIScriptAlias / /srv/kallithea/dispatch.wsgi
805 WSGIScriptAlias / /srv/kallithea/dispatch.wsgi
803 WSGIPassAuthorization On
806 WSGIPassAuthorization On
804
807
805 Or if using a dispatcher WSGI script with proper virtualenv activation:
808 Or if using a dispatcher WSGI script with proper virtualenv activation:
806
809
807 .. code-block:: apache
810 .. code-block:: apache
808
811
809 WSGIDaemonProcess kallithea processes=5 threads=1 maximum-requests=100
812 WSGIDaemonProcess kallithea processes=5 threads=1 maximum-requests=100
810 WSGIProcessGroup kallithea
813 WSGIProcessGroup kallithea
811 WSGIScriptAlias / /srv/kallithea/dispatch.wsgi
814 WSGIScriptAlias / /srv/kallithea/dispatch.wsgi
812 WSGIPassAuthorization On
815 WSGIPassAuthorization On
813
816
814 Apache will by default run as a special Apache user, on Linux systems
817 Apache will by default run as a special Apache user, on Linux systems
815 usually ``www-data`` or ``apache``. If you need to have the repositories
818 usually ``www-data`` or ``apache``. If you need to have the repositories
816 directory owned by a different user, use the user and group options to
819 directory owned by a different user, use the user and group options to
817 WSGIDaemonProcess to set the name of the user and group.
820 WSGIDaemonProcess to set the name of the user and group.
818
821
819 Example WSGI dispatch script:
822 Example WSGI dispatch script:
820
823
821 .. code-block:: python
824 .. code-block:: python
822
825
823 import os
826 import os
824 os.environ["HGENCODING"] = "UTF-8"
827 os.environ["HGENCODING"] = "UTF-8"
825 os.environ['PYTHON_EGG_CACHE'] = '/srv/kallithea/.egg-cache'
828 os.environ['PYTHON_EGG_CACHE'] = '/srv/kallithea/.egg-cache'
826
829
827 # sometimes it's needed to set the current dir
830 # sometimes it's needed to set the current dir
828 os.chdir('/srv/kallithea/')
831 os.chdir('/srv/kallithea/')
829
832
830 import site
833 import site
831 site.addsitedir("/srv/kallithea/venv/lib/python2.7/site-packages")
834 site.addsitedir("/srv/kallithea/venv/lib/python2.7/site-packages")
832
835
833 ini = '/srv/kallithea/my.ini'
836 ini = '/srv/kallithea/my.ini'
834 from paste.script.util.logging_config import fileConfig
837 from paste.script.util.logging_config import fileConfig
835 fileConfig(ini)
838 fileConfig(ini)
836 from paste.deploy import loadapp
839 from paste.deploy import loadapp
837 application = loadapp('config:' + ini)
840 application = loadapp('config:' + ini)
838
841
839 Or using proper virtualenv activation:
842 Or using proper virtualenv activation:
840
843
841 .. code-block:: python
844 .. code-block:: python
842
845
843 activate_this = '/srv/kallithea/venv/bin/activate_this.py'
846 activate_this = '/srv/kallithea/venv/bin/activate_this.py'
844 execfile(activate_this, dict(__file__=activate_this))
847 execfile(activate_this, dict(__file__=activate_this))
845
848
846 import os
849 import os
847 os.environ['HOME'] = '/srv/kallithea'
850 os.environ['HOME'] = '/srv/kallithea'
848
851
849 ini = '/srv/kallithea/kallithea.ini'
852 ini = '/srv/kallithea/kallithea.ini'
850 from paste.script.util.logging_config import fileConfig
853 from paste.script.util.logging_config import fileConfig
851 fileConfig(ini)
854 fileConfig(ini)
852 from paste.deploy import loadapp
855 from paste.deploy import loadapp
853 application = loadapp('config:' + ini)
856 application = loadapp('config:' + ini)
854
857
855
858
856 Other configuration files
859 Other configuration files
857 -------------------------
860 -------------------------
858
861
859 A number of `example init.d scripts`__ can be found in
862 A number of `example init.d scripts`__ can be found in
860 the ``init.d`` directory of the Kallithea source.
863 the ``init.d`` directory of the Kallithea source.
861
864
862 .. __: https://kallithea-scm.org/repos/kallithea/files/tip/init.d/ .
865 .. __: https://kallithea-scm.org/repos/kallithea/files/tip/init.d/ .
863
866
864
867
865 .. _virtualenv: http://pypi.python.org/pypi/virtualenv
868 .. _virtualenv: http://pypi.python.org/pypi/virtualenv
866 .. _python: http://www.python.org/
869 .. _python: http://www.python.org/
867 .. _Mercurial: https://www.mercurial-scm.org/
870 .. _Mercurial: https://www.mercurial-scm.org/
868 .. _Celery: http://celeryproject.org/
871 .. _Celery: http://celeryproject.org/
869 .. _Celery documentation: http://docs.celeryproject.org/en/latest/getting-started/index.html
872 .. _Celery documentation: http://docs.celeryproject.org/en/latest/getting-started/index.html
870 .. _RabbitMQ: http://www.rabbitmq.com/
873 .. _RabbitMQ: http://www.rabbitmq.com/
871 .. _Redis: http://redis.io/
874 .. _Redis: http://redis.io/
872 .. _python-ldap: http://www.python-ldap.org/
875 .. _python-ldap: http://www.python-ldap.org/
873 .. _mercurial-server: http://www.lshift.net/mercurial-server.html
876 .. _mercurial-server: http://www.lshift.net/mercurial-server.html
874 .. _PublishingRepositories: https://www.mercurial-scm.org/wiki/PublishingRepositories
877 .. _PublishingRepositories: https://www.mercurial-scm.org/wiki/PublishingRepositories
@@ -1,187 +1,187 b''
1 .. _upgrade:
1 .. _upgrade:
2
2
3 ===================
3 ===================
4 Upgrading Kallithea
4 Upgrading Kallithea
5 ===================
5 ===================
6
6
7 This describes the process for upgrading Kallithea, independently of the
7 This describes the process for upgrading Kallithea, independently of the
8 Kallithea installation method.
8 Kallithea installation method.
9
9
10 .. note::
10 .. note::
11 If you are upgrading from a RhodeCode installation, you must first
11 If you are upgrading from a RhodeCode installation, you must first
12 install Kallithea 0.3.2 and follow the instructions in the 0.3.2
12 install Kallithea 0.3.2 and follow the instructions in the 0.3.2
13 README to perform a one-time conversion of the database from
13 README to perform a one-time conversion of the database from
14 RhodeCode to Kallithea, before upgrading to the latest version
14 RhodeCode to Kallithea, before upgrading to the latest version
15 of Kallithea.
15 of Kallithea.
16
16
17
17
18 1. Stop the Kallithea web application
18 1. Stop the Kallithea web application
19 -------------------------------------
19 -------------------------------------
20
20
21 This step depends entirely on the web server software used to serve
21 This step depends entirely on the web server software used to serve
22 Kallithea, but in any case, Kallithea should not be running during
22 Kallithea, but in any case, Kallithea should not be running during
23 the upgrade.
23 the upgrade.
24
24
25 .. note::
25 .. note::
26 If you're using Celery, make sure you stop all instances during the
26 If you're using Celery, make sure you stop all instances during the
27 upgrade.
27 upgrade.
28
28
29
29
30 2. Create a backup of both database and configuration
30 2. Create a backup of both database and configuration
31 -----------------------------------------------------
31 -----------------------------------------------------
32
32
33 You are of course strongly recommended to make backups regularly, but it
33 You are of course strongly recommended to make backups regularly, but it
34 is *especially* important to make a full database and configuration
34 is *especially* important to make a full database and configuration
35 backup before performing a Kallithea upgrade.
35 backup before performing a Kallithea upgrade.
36
36
37 Back up your configuration
37 Back up your configuration
38 ^^^^^^^^^^^^^^^^^^^^^^^^^^
38 ^^^^^^^^^^^^^^^^^^^^^^^^^^
39
39
40 Make a copy of your Kallithea configuration (``.ini``) file.
40 Make a copy of your Kallithea configuration (``.ini``) file.
41
41
42 If you are using :ref:`rcextensions <customization>`, you should also
42 If you are using :ref:`rcextensions <customization>`, you should also
43 make a copy of the entire ``rcextensions`` directory.
43 make a copy of the entire ``rcextensions`` directory.
44
44
45 Back up your database
45 Back up your database
46 ^^^^^^^^^^^^^^^^^^^^^
46 ^^^^^^^^^^^^^^^^^^^^^
47
47
48 If using SQLite, simply make a copy of the Kallithea database (``.db``)
48 If using SQLite, simply make a copy of the Kallithea database (``.db``)
49 file.
49 file.
50
50
51 If using PostgreSQL, please consult the documentation for the ``pg_dump``
51 If using PostgreSQL, please consult the documentation for the ``pg_dump``
52 utility.
52 utility.
53
53
54 If using MySQL, please consult the documentation for the ``mysqldump``
54 If using MySQL, please consult the documentation for the ``mysqldump``
55 utility.
55 utility.
56
56
57 Look for ``sqlalchemy.url`` in your configuration file to determine
57 Look for ``sqlalchemy.url`` in your configuration file to determine
58 database type, settings, location, etc.
58 database type, settings, location, etc.
59
59
60
60
61 3. Activate the Kallithea virtual environment (if any)
61 3. Activate the Kallithea virtual environment (if any)
62 ------------------------------------------------------
62 ------------------------------------------------------
63
63
64 Verify that you are using the Python environment that you originally
64 Verify that you are using the Python environment that you originally
65 installed Kallithea in by running::
65 installed Kallithea in by running::
66
66
67 pip freeze
67 pip freeze
68
68
69 This will list all packages installed in the current environment. If
69 This will list all packages installed in the current environment. If
70 Kallithea isn't listed, activate the correct virtual environment.
70 Kallithea isn't listed, activate the correct virtual environment.
71 See the appropriate installation page for details.
71 See the appropriate installation page for details.
72
72
73
73
74 4. Install new version of Kallithea
74 4. Install new version of Kallithea
75 -----------------------------------
75 -----------------------------------
76
76
77 Please refer to the instructions for the installation method you
77 Please refer to the instructions for the installation method you
78 originally used to install Kallithea.
78 originally used to install Kallithea.
79
79
80 If you originally installed using pip, it is as simple as::
80 If you originally installed using pip, it is as simple as::
81
81
82 pip install --upgrade kallithea
82 pip install --upgrade kallithea
83
83
84 If you originally installed from version control, it is as simple as::
84 If you originally installed from version control, it is as simple as::
85
85
86 cd my-kallithea-clone
86 cd my-kallithea-clone
87 hg pull -u
87 hg pull -u
88 pip install -e .
88 pip install -e .
89
89
90
90
91 5. Upgrade your configuration
91 5. Upgrade your configuration
92 -----------------------------
92 -----------------------------
93
93
94 Run the following command to upgrade your configuration (``.ini``) file::
94 Run the following command to upgrade your configuration (``.ini``) file::
95
95
96 paster make-config Kallithea my.ini
96 TODO make-config Kallithea my.ini
97
97
98 This will display any changes made by the new version of Kallithea to your
98 This will display any changes made by the new version of Kallithea to your
99 current configuration, and attempt an automatic merge. It is recommended
99 current configuration, and attempt an automatic merge. It is recommended
100 that you check the contents after the merge.
100 that you check the contents after the merge.
101
101
102 .. note::
102 .. note::
103 Please always make sure your ``.ini`` files are up to date. Errors
103 Please always make sure your ``.ini`` files are up to date. Errors
104 can often be caused by missing parameters added in new versions.
104 can often be caused by missing parameters added in new versions.
105
105
106 .. _upgrade_db:
106 .. _upgrade_db:
107
107
108
108
109 6. Upgrade your database
109 6. Upgrade your database
110 ------------------------
110 ------------------------
111
111
112 .. note::
112 .. note::
113 If you are *downgrading* Kallithea, you should perform the database
113 If you are *downgrading* Kallithea, you should perform the database
114 migration step *before* installing the older version. (That is,
114 migration step *before* installing the older version. (That is,
115 always perform migrations using the most recent of the two versions
115 always perform migrations using the most recent of the two versions
116 you're migrating between.)
116 you're migrating between.)
117
117
118 First, run the following command to see your current database version::
118 First, run the following command to see your current database version::
119
119
120 alembic -c my.ini current
120 alembic -c my.ini current
121
121
122 Typical output will be something like "9358dc3d6828 (head)", which is
122 Typical output will be something like "9358dc3d6828 (head)", which is
123 the current Alembic database "revision ID". Write down the entire output
123 the current Alembic database "revision ID". Write down the entire output
124 for troubleshooting purposes.
124 for troubleshooting purposes.
125
125
126 The output will be empty if you're upgrading from Kallithea 0.3.x or
126 The output will be empty if you're upgrading from Kallithea 0.3.x or
127 older. That's expected. If you get an error that the config file was not
127 older. That's expected. If you get an error that the config file was not
128 found or has no ``[alembic]`` section, see the next section.
128 found or has no ``[alembic]`` section, see the next section.
129
129
130 Next, if you are performing an *upgrade*: Run the following command to
130 Next, if you are performing an *upgrade*: Run the following command to
131 upgrade your database to the current Kallithea version::
131 upgrade your database to the current Kallithea version::
132
132
133 alembic -c my.ini upgrade head
133 alembic -c my.ini upgrade head
134
134
135 If you are performing a *downgrade*: Run the following command to
135 If you are performing a *downgrade*: Run the following command to
136 downgrade your database to the given version::
136 downgrade your database to the given version::
137
137
138 alembic -c my.ini downgrade 0.4
138 alembic -c my.ini downgrade 0.4
139
139
140 Alembic will show the necessary migrations (if any) as it executes them.
140 Alembic will show the necessary migrations (if any) as it executes them.
141 If no "ERROR" is displayed, the command was successful.
141 If no "ERROR" is displayed, the command was successful.
142
142
143 Should an error occur, the database may be "stranded" half-way
143 Should an error occur, the database may be "stranded" half-way
144 through the migration, and you should restore it from backup.
144 through the migration, and you should restore it from backup.
145
145
146 Enabling old Kallithea config files for Alembic use
146 Enabling old Kallithea config files for Alembic use
147 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
147 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
148
148
149 Kallithea configuration files created before the introduction of Alembic
149 Kallithea configuration files created before the introduction of Alembic
150 (i.e. predating Kallithea 0.4) need to be updated for use with Alembic.
150 (i.e. predating Kallithea 0.4) need to be updated for use with Alembic.
151 Without this, Alembic will fail with an error like this::
151 Without this, Alembic will fail with an error like this::
152
152
153 FAILED: No config file 'my.ini' found, or file has no '[alembic]' section
153 FAILED: No config file 'my.ini' found, or file has no '[alembic]' section
154
154
155 If Alembic complains specifically about a missing ``alembic.ini``, it is
155 If Alembic complains specifically about a missing ``alembic.ini``, it is
156 likely because you did not specify a config file using the ``-c`` option.
156 likely because you did not specify a config file using the ``-c`` option.
157 On the other hand, if the mentioned config file actually exists, you
157 On the other hand, if the mentioned config file actually exists, you
158 need to append the following lines to it::
158 need to append the following lines to it::
159
159
160 [alembic]
160 [alembic]
161 script_location = kallithea:alembic
161 script_location = kallithea:alembic
162
162
163 Your config file should now work with Alembic.
163 Your config file should now work with Alembic.
164
164
165
165
166 7. Rebuild the Whoosh full-text index
166 7. Rebuild the Whoosh full-text index
167 -------------------------------------
167 -------------------------------------
168
168
169 It is recommended that you rebuild the Whoosh index after upgrading since
169 It is recommended that you rebuild the Whoosh index after upgrading since
170 new Whoosh versions can introduce incompatible index changes.
170 new Whoosh versions can introduce incompatible index changes.
171
171
172
172
173 8. Start the Kallithea web application
173 8. Start the Kallithea web application
174 --------------------------------------
174 --------------------------------------
175
175
176 This step once again depends entirely on the web server software used to
176 This step once again depends entirely on the web server software used to
177 serve Kallithea.
177 serve Kallithea.
178
178
179 Before starting the new version of Kallithea, you may find it helpful to
179 Before starting the new version of Kallithea, you may find it helpful to
180 clear out your log file so that new errors are readily apparent.
180 clear out your log file so that new errors are readily apparent.
181
181
182 .. note::
182 .. note::
183 If you're using Celery, make sure you restart all instances of it after
183 If you're using Celery, make sure you restart all instances of it after
184 upgrade.
184 upgrade.
185
185
186
186
187 .. _virtualenv: http://pypi.python.org/pypi/virtualenv
187 .. _virtualenv: http://pypi.python.org/pypi/virtualenv
@@ -1,50 +1,50 b''
1 .. _customization:
1 .. _customization:
2
2
3 =============
3 =============
4 Customization
4 Customization
5 =============
5 =============
6
6
7 There are several ways to customize Kallithea to your needs depending on what
7 There are several ways to customize Kallithea to your needs depending on what
8 you want to achieve.
8 you want to achieve.
9
9
10
10
11 HTML/JavaScript/CSS customization
11 HTML/JavaScript/CSS customization
12 ---------------------------------
12 ---------------------------------
13
13
14 To customize the look-and-feel of the web interface (for example to add a
14 To customize the look-and-feel of the web interface (for example to add a
15 company banner or some JavaScript widget or to tweak the CSS style definitions)
15 company banner or some JavaScript widget or to tweak the CSS style definitions)
16 you can enter HTML code (possibly with JavaScript and/or CSS) directly via the
16 you can enter HTML code (possibly with JavaScript and/or CSS) directly via the
17 *Admin > Settings > Global > HTML/JavaScript customization
17 *Admin > Settings > Global > HTML/JavaScript customization
18 block*.
18 block*.
19
19
20
20
21 Behavioral customization: rcextensions
21 Behavioral customization: rcextensions
22 --------------------------------------
22 --------------------------------------
23
23
24 Some behavioral customization can be done in Python using ``rcextensions``, a
24 Some behavioral customization can be done in Python using ``rcextensions``, a
25 custom Python package that can extend Kallithea functionality.
25 custom Python package that can extend Kallithea functionality.
26
26
27 With ``rcextensions`` it's possible to add additional mappings for Whoosh
27 With ``rcextensions`` it's possible to add additional mappings for Whoosh
28 indexing and statistics, to add additional code into the push/pull/create/delete
28 indexing and statistics, to add additional code into the push/pull/create/delete
29 repository hooks (for example to send signals to build bots such as Jenkins) and
29 repository hooks (for example to send signals to build bots such as Jenkins) and
30 even to monkey-patch certain parts of the Kallithea source code (for example
30 even to monkey-patch certain parts of the Kallithea source code (for example
31 overwrite an entire function, change a global variable, ...).
31 overwrite an entire function, change a global variable, ...).
32
32
33 To generate a skeleton extensions package, run::
33 To generate a skeleton extensions package, run::
34
34
35 paster make-rcext my.ini
35 gearbox make-rcext -c my.ini
36
36
37 This will create an ``rcextensions`` package next to the specified ``ini`` file.
37 This will create an ``rcextensions`` package next to the specified ``ini`` file.
38 See the ``__init__.py`` file inside the generated ``rcextensions`` package
38 See the ``__init__.py`` file inside the generated ``rcextensions`` package
39 for more details.
39 for more details.
40
40
41
41
42 Behavioral customization: code changes
42 Behavioral customization: code changes
43 --------------------------------------
43 --------------------------------------
44
44
45 As Kallithea is open-source software, you can make any changes you like directly
45 As Kallithea is open-source software, you can make any changes you like directly
46 in the source code.
46 in the source code.
47
47
48 We encourage you to send generic improvements back to the
48 We encourage you to send generic improvements back to the
49 community so that Kallithea can become better. See :ref:`contributing` for more
49 community so that Kallithea can become better. See :ref:`contributing` for more
50 details.
50 details.
@@ -1,181 +1,181 b''
1 .. _general:
1 .. _general:
2
2
3 =======================
3 =======================
4 General Kallithea usage
4 General Kallithea usage
5 =======================
5 =======================
6
6
7
7
8 Repository deletion
8 Repository deletion
9 -------------------
9 -------------------
10
10
11 Currently when an admin or owner deletes a repository, Kallithea does
11 Currently when an admin or owner deletes a repository, Kallithea does
12 not physically delete said repository from the filesystem, but instead
12 not physically delete said repository from the filesystem, but instead
13 renames it in a special way so that it is not possible to push, clone
13 renames it in a special way so that it is not possible to push, clone
14 or access the repository.
14 or access the repository.
15
15
16 There is a special command for cleaning up such archived repositories::
16 There is a special command for cleaning up such archived repositories::
17
17
18 paster cleanup-repos --older-than=30d my.ini
18 gearbox cleanup-repos --older-than=30d -c my.ini
19
19
20 This command scans for archived repositories that are older than
20 This command scans for archived repositories that are older than
21 30 days, displays them, and asks if you want to delete them (unless given
21 30 days, displays them, and asks if you want to delete them (unless given
22 the ``--dont-ask`` flag). If you host a large amount of repositories with
22 the ``--dont-ask`` flag). If you host a large amount of repositories with
23 forks that are constantly being deleted, it is recommended that you run this
23 forks that are constantly being deleted, it is recommended that you run this
24 command via crontab.
24 command via crontab.
25
25
26 It is worth noting that even if someone is given administrative access to
26 It is worth noting that even if someone is given administrative access to
27 Kallithea and deletes a repository, you can easily restore such an action by
27 Kallithea and deletes a repository, you can easily restore such an action by
28 renaming the repository directory, removing the ``rm__<date>`` prefix.
28 renaming the repository directory, removing the ``rm__<date>`` prefix.
29
29
30
30
31 File view: follow current branch
31 File view: follow current branch
32 --------------------------------
32 --------------------------------
33
33
34 In the file view, left and right arrows allow to jump to the previous and next
34 In the file view, left and right arrows allow to jump to the previous and next
35 revision. Depending on the way revisions were created in the repository, this
35 revision. Depending on the way revisions were created in the repository, this
36 could jump to a different branch. When the checkbox ``Follow current branch``
36 could jump to a different branch. When the checkbox ``Follow current branch``
37 is checked, these arrows will only jump to revisions on the same branch as the
37 is checked, these arrows will only jump to revisions on the same branch as the
38 currently visible revision. So for example, if someone is viewing files in the
38 currently visible revision. So for example, if someone is viewing files in the
39 ``beta`` branch and marks the `Follow current branch` checkbox, the < and >
39 ``beta`` branch and marks the `Follow current branch` checkbox, the < and >
40 arrows will only show revisions on the ``beta`` branch.
40 arrows will only show revisions on the ``beta`` branch.
41
41
42
42
43 Changelog features
43 Changelog features
44 ------------------
44 ------------------
45
45
46 The core feature of a repository's ``changelog`` page is to show the revisions
46 The core feature of a repository's ``changelog`` page is to show the revisions
47 in a repository. However, there are several other features available from the
47 in a repository. However, there are several other features available from the
48 changelog.
48 changelog.
49
49
50 Branch filter
50 Branch filter
51 By default, the changelog shows revisions from all branches in the
51 By default, the changelog shows revisions from all branches in the
52 repository. Use the branch filter to restrict to a given branch.
52 repository. Use the branch filter to restrict to a given branch.
53
53
54 Viewing a changeset
54 Viewing a changeset
55 A particular changeset can be opened by clicking on either the changeset
55 A particular changeset can be opened by clicking on either the changeset
56 hash or the commit message, or by ticking the checkbox and clicking the
56 hash or the commit message, or by ticking the checkbox and clicking the
57 ``Show selected changeset`` button at the top.
57 ``Show selected changeset`` button at the top.
58
58
59 Viewing all changes between two changesets
59 Viewing all changes between two changesets
60 To get a list of all changesets between two selected changesets, along with
60 To get a list of all changesets between two selected changesets, along with
61 the changes in each one of them, tick the checkboxes of the first and
61 the changes in each one of them, tick the checkboxes of the first and
62 last changeset in the desired range and click the ``Show selected changesets``
62 last changeset in the desired range and click the ``Show selected changesets``
63 button at the top. You can only show the range between the first and last
63 button at the top. You can only show the range between the first and last
64 checkbox (no cherry-picking).
64 checkbox (no cherry-picking).
65
65
66 From that page, you can proceed to viewing the overall delta between the
66 From that page, you can proceed to viewing the overall delta between the
67 selected changesets, by clicking the ``Compare revisions`` button.
67 selected changesets, by clicking the ``Compare revisions`` button.
68
68
69 Creating a pull request
69 Creating a pull request
70 You can create a new pull request for the changes of a particular changeset
70 You can create a new pull request for the changes of a particular changeset
71 (and its ancestors) by selecting it and clicking the ``Open new pull request
71 (and its ancestors) by selecting it and clicking the ``Open new pull request
72 for selected changesets`` button.
72 for selected changesets`` button.
73
73
74
74
75 Permanent repository URLs
75 Permanent repository URLs
76 -------------------------
76 -------------------------
77
77
78 Due to the complicated nature of repository grouping, URLs of repositories
78 Due to the complicated nature of repository grouping, URLs of repositories
79 can often change. For example, a repository originally accessible from::
79 can often change. For example, a repository originally accessible from::
80
80
81 http://kallithea.example.com/repo_name
81 http://kallithea.example.com/repo_name
82
82
83 would get a new URL after moving it to test_group::
83 would get a new URL after moving it to test_group::
84
84
85 http://kallithea.example.com/test_group/repo_name
85 http://kallithea.example.com/test_group/repo_name
86
86
87 Such moving of a repository to a group can be an issue for build systems and
87 Such moving of a repository to a group can be an issue for build systems and
88 other scripts where the repository paths are hardcoded. To mitigate this,
88 other scripts where the repository paths are hardcoded. To mitigate this,
89 Kallithea provides permanent URLs using the repository ID prefixed with an
89 Kallithea provides permanent URLs using the repository ID prefixed with an
90 underscore. In all Kallithea URLs, for example those for the changelog and the
90 underscore. In all Kallithea URLs, for example those for the changelog and the
91 file view, a repository name can be replaced by this ``_ID`` string. Since IDs
91 file view, a repository name can be replaced by this ``_ID`` string. Since IDs
92 are always the same, moving the repository to a different group will not affect
92 are always the same, moving the repository to a different group will not affect
93 such URLs.
93 such URLs.
94
94
95 In the example, the repository could also be accessible as::
95 In the example, the repository could also be accessible as::
96
96
97 http://kallithea.example.com/_<ID>
97 http://kallithea.example.com/_<ID>
98
98
99 The ID of a given repository can be shown from the repository ``Summary`` page,
99 The ID of a given repository can be shown from the repository ``Summary`` page,
100 by selecting the ``Show by ID`` button next to ``Clone URL``.
100 by selecting the ``Show by ID`` button next to ``Clone URL``.
101
101
102
102
103 Email notifications
103 Email notifications
104 -------------------
104 -------------------
105
105
106 With email settings properly configured in the Kallithea
106 With email settings properly configured in the Kallithea
107 configuration file, Kallithea will send emails on user registration and when
107 configuration file, Kallithea will send emails on user registration and when
108 errors occur.
108 errors occur.
109
109
110 Emails are also sent for comments on changesets. In this case, an email is sent
110 Emails are also sent for comments on changesets. In this case, an email is sent
111 to the committer of the changeset (if known to Kallithea), to all reviewers of
111 to the committer of the changeset (if known to Kallithea), to all reviewers of
112 the pull request (if applicable) and to all people mentioned in the comment
112 the pull request (if applicable) and to all people mentioned in the comment
113 using @mention notation.
113 using @mention notation.
114
114
115
115
116 Trending source files
116 Trending source files
117 ---------------------
117 ---------------------
118
118
119 Trending source files are calculated based on a predefined dictionary of known
119 Trending source files are calculated based on a predefined dictionary of known
120 types and extensions. If an extension is missing or you would like to scan
120 types and extensions. If an extension is missing or you would like to scan
121 custom files, it is possible to extend the ``LANGUAGES_EXTENSIONS_MAP``
121 custom files, it is possible to extend the ``LANGUAGES_EXTENSIONS_MAP``
122 dictionary located in ``kallithea/config/conf.py`` with new types.
122 dictionary located in ``kallithea/config/conf.py`` with new types.
123
123
124
124
125 Cloning remote repositories
125 Cloning remote repositories
126 ---------------------------
126 ---------------------------
127
127
128 Kallithea has the ability to clone repositories from given remote locations.
128 Kallithea has the ability to clone repositories from given remote locations.
129 Currently it supports the following options:
129 Currently it supports the following options:
130
130
131 - hg -> hg clone
131 - hg -> hg clone
132 - svn -> hg clone
132 - svn -> hg clone
133 - git -> git clone
133 - git -> git clone
134
134
135 .. note:: svn -> hg cloning requires the ``hgsubversion`` library to be
135 .. note:: svn -> hg cloning requires the ``hgsubversion`` library to be
136 installed.
136 installed.
137
137
138 If you need to clone repositories that are protected via basic authentication,
138 If you need to clone repositories that are protected via basic authentication,
139 you can pass the credentials in the URL, e.g.
139 you can pass the credentials in the URL, e.g.
140 ``http://user:passw@remote.example.com/repo``. Kallithea will then try to login and
140 ``http://user:passw@remote.example.com/repo``. Kallithea will then try to login and
141 clone using the given credentials. Please note that the given credentials will
141 clone using the given credentials. Please note that the given credentials will
142 be stored as plaintext inside the database. However, the authentication
142 be stored as plaintext inside the database. However, the authentication
143 information will not be shown in the clone URL on the summary page.
143 information will not be shown in the clone URL on the summary page.
144
144
145
145
146 Specific features configurable in the Admin settings
146 Specific features configurable in the Admin settings
147 ----------------------------------------------------
147 ----------------------------------------------------
148
148
149 In general, the Admin settings should be self-explanatory and will not be
149 In general, the Admin settings should be self-explanatory and will not be
150 described in more detail in this documentation. However, there are a few
150 described in more detail in this documentation. However, there are a few
151 features that merit further explanation.
151 features that merit further explanation.
152
152
153 Repository extra fields
153 Repository extra fields
154 ^^^^^^^^^^^^^^^^^^^^^^^
154 ^^^^^^^^^^^^^^^^^^^^^^^
155
155
156 In the *Visual* tab, there is an option "Use repository extra
156 In the *Visual* tab, there is an option "Use repository extra
157 fields", which allows to set custom fields for each repository in the system.
157 fields", which allows to set custom fields for each repository in the system.
158
158
159 Once enabled site-wide, the custom fields can be edited per-repository under
159 Once enabled site-wide, the custom fields can be edited per-repository under
160 *Options* | *Settings* | *Extra Fields*.
160 *Options* | *Settings* | *Extra Fields*.
161
161
162 Example usage of such fields would be to define company-specific information
162 Example usage of such fields would be to define company-specific information
163 into repositories, e.g., defining a ``repo_manager`` key that would give info
163 into repositories, e.g., defining a ``repo_manager`` key that would give info
164 about a manager of each repository. There's no limit for adding custom fields.
164 about a manager of each repository. There's no limit for adding custom fields.
165 Newly created fields are accessible via the API.
165 Newly created fields are accessible via the API.
166
166
167 Meta tagging
167 Meta tagging
168 ^^^^^^^^^^^^
168 ^^^^^^^^^^^^
169
169
170 In the *Visual* tab, option "Stylify recognised meta tags" will cause Kallithea
170 In the *Visual* tab, option "Stylify recognised meta tags" will cause Kallithea
171 to turn certain text fragments in repository and repository group
171 to turn certain text fragments in repository and repository group
172 descriptions into colored tags. Currently recognised tags are::
172 descriptions into colored tags. Currently recognised tags are::
173
173
174 [featured]
174 [featured]
175 [stale]
175 [stale]
176 [dead]
176 [dead]
177 [lang => lang]
177 [lang => lang]
178 [license => License]
178 [license => License]
179 [requires => Repo]
179 [requires => Repo]
180 [recommends => Repo]
180 [recommends => Repo]
181 [see => URI]
181 [see => URI]
@@ -1,87 +1,87 b''
1 .. _vcs_support:
1 .. _vcs_support:
2
2
3 ===============================
3 ===============================
4 Version control systems support
4 Version control systems support
5 ===============================
5 ===============================
6
6
7 Kallithea supports Git and Mercurial repositories out-of-the-box.
7 Kallithea supports Git and Mercurial repositories out-of-the-box.
8 For Git, you do need the ``git`` command line client installed on the server.
8 For Git, you do need the ``git`` command line client installed on the server.
9
9
10 You can always disable Git or Mercurial support by editing the
10 You can always disable Git or Mercurial support by editing the
11 file ``kallithea/__init__.py`` and commenting out the backend.
11 file ``kallithea/__init__.py`` and commenting out the backend.
12
12
13 .. code-block:: python
13 .. code-block:: python
14
14
15 BACKENDS = {
15 BACKENDS = {
16 'hg': 'Mercurial repository',
16 'hg': 'Mercurial repository',
17 #'git': 'Git repository',
17 #'git': 'Git repository',
18 }
18 }
19
19
20
20
21 Git support
21 Git support
22 -----------
22 -----------
23
23
24
24
25 Web server with chunked encoding
25 Web server with chunked encoding
26 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
26 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
27
27
28 Large Git pushes require an HTTP server with support for
28 Large Git pushes require an HTTP server with support for
29 chunked encoding for POST. The Python web servers waitress_ and
29 chunked encoding for POST. The Python web servers waitress_ and
30 gunicorn_ (Linux only) can be used. By default, Kallithea uses
30 gunicorn_ (Linux only) can be used. By default, Kallithea uses
31 waitress_ for `paster serve` instead of the built-in `paste` WSGI
31 waitress_ for `gearbox serve` instead of the built-in `paste` WSGI
32 server.
32 server.
33
33
34 The paster server is controlled in the .ini file::
34 The web server used by gearbox is controlled in the .ini file::
35
35
36 use = egg:waitress#main
36 use = egg:waitress#main
37
37
38 or::
38 or::
39
39
40 use = egg:gunicorn#main
40 use = egg:gunicorn#main
41
41
42 Also make sure to comment out the following options::
42 Also make sure to comment out the following options::
43
43
44 threadpool_workers =
44 threadpool_workers =
45 threadpool_max_requests =
45 threadpool_max_requests =
46 use_threadpool =
46 use_threadpool =
47
47
48
48
49 Mercurial support
49 Mercurial support
50 -----------------
50 -----------------
51
51
52
52
53 Working with Mercurial subrepositories
53 Working with Mercurial subrepositories
54 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
54 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
55
55
56 This section explains how to use Mercurial subrepositories_ in Kallithea.
56 This section explains how to use Mercurial subrepositories_ in Kallithea.
57
57
58 Example usage::
58 Example usage::
59
59
60 ## init a simple repo
60 ## init a simple repo
61 hg init mainrepo
61 hg init mainrepo
62 cd mainrepo
62 cd mainrepo
63 echo "file" > file
63 echo "file" > file
64 hg add file
64 hg add file
65 hg ci --message "initial file"
65 hg ci --message "initial file"
66
66
67 # clone subrepo we want to add from Kallithea
67 # clone subrepo we want to add from Kallithea
68 hg clone http://kallithea.local/subrepo
68 hg clone http://kallithea.local/subrepo
69
69
70 ## specify URL to existing repo in Kallithea as subrepository path
70 ## specify URL to existing repo in Kallithea as subrepository path
71 echo "subrepo = http://kallithea.local/subrepo" > .hgsub
71 echo "subrepo = http://kallithea.local/subrepo" > .hgsub
72 hg add .hgsub
72 hg add .hgsub
73 hg ci --message "added remote subrepo"
73 hg ci --message "added remote subrepo"
74
74
75 In the file list of a clone of ``mainrepo`` you will see a connected
75 In the file list of a clone of ``mainrepo`` you will see a connected
76 subrepository at the revision it was cloned with. Clicking on the
76 subrepository at the revision it was cloned with. Clicking on the
77 subrepository link sends you to the proper repository in Kallithea.
77 subrepository link sends you to the proper repository in Kallithea.
78
78
79 Cloning ``mainrepo`` will also clone the attached subrepository.
79 Cloning ``mainrepo`` will also clone the attached subrepository.
80
80
81 Next we can edit the subrepository data, and push back to Kallithea. This will
81 Next we can edit the subrepository data, and push back to Kallithea. This will
82 update both repositories.
82 update both repositories.
83
83
84
84
85 .. _waitress: http://pypi.python.org/pypi/waitress
85 .. _waitress: http://pypi.python.org/pypi/waitress
86 .. _gunicorn: http://pypi.python.org/pypi/gunicorn
86 .. _gunicorn: http://pypi.python.org/pypi/gunicorn
87 .. _subrepositories: http://mercurial.aragost.com/kick-start/en/subrepositories/
87 .. _subrepositories: http://mercurial.aragost.com/kick-start/en/subrepositories/
@@ -1,34 +1,34 b''
1 # celeryd - run the celeryd daemon as an upstart job for kallithea
1 # celeryd - run the celeryd daemon as an upstart job for kallithea
2 # Change variables/paths as necessary and place file /etc/init/celeryd.conf
2 # Change variables/paths as necessary and place file /etc/init/celeryd.conf
3 # start/stop/restart as normal upstart job (ie: $ start celeryd)
3 # start/stop/restart as normal upstart job (ie: $ start celeryd)
4
4
5 description "Celery for Kallithea Mercurial Server"
5 description "Celery for Kallithea Mercurial Server"
6 author "Matt Zuba <matt.zuba@goodwillaz.org"
6 author "Matt Zuba <matt.zuba@goodwillaz.org"
7
7
8 start on starting kallithea
8 start on starting kallithea
9 stop on stopped kallithea
9 stop on stopped kallithea
10
10
11 respawn
11 respawn
12
12
13 umask 0022
13 umask 0022
14
14
15 env PIDFILE=/tmp/celeryd.pid
15 env PIDFILE=/tmp/celeryd.pid
16 env APPINI=/var/hg/kallithea/production.ini
16 env APPINI=/var/hg/kallithea/production.ini
17 env HOME=/var/hg
17 env HOME=/var/hg
18 env USER=hg
18 env USER=hg
19 # To use group (if different from user), you must edit sudoers file and change
19 # To use group (if different from user), you must edit sudoers file and change
20 # root's entry from (ALL) to (ALL:ALL)
20 # root's entry from (ALL) to (ALL:ALL)
21 # env GROUP=hg
21 # env GROUP=hg
22
22
23 script
23 script
24 COMMAND="/var/hg/.virtualenvs/kallithea/bin/paster celeryd $APPINI --pidfile=$PIDFILE"
24 COMMAND="/var/hg/.virtualenvs/kallithea/bin/gearbox celeryd -c $APPINI -- --pidfile=$PIDFILE"
25 if [ -z "$GROUP" ]; then
25 if [ -z "$GROUP" ]; then
26 exec sudo -u $USER $COMMAND
26 exec sudo -u $USER $COMMAND
27 else
27 else
28 exec sudo -u $USER -g $GROUP $COMMAND
28 exec sudo -u $USER -g $GROUP $COMMAND
29 fi
29 fi
30 end script
30 end script
31
31
32 post-stop script
32 post-stop script
33 rm -f $PIDFILE
33 rm -f $PIDFILE
34 end script
34 end script
@@ -1,70 +1,70 b''
1 #!/bin/bash
1 #!/bin/bash
2 ###########################################
2 ###########################################
3 #### THIS IS AN ARCH LINUX RC.D SCRIPT ####
3 #### THIS IS AN ARCH LINUX RC.D SCRIPT ####
4 ###########################################
4 ###########################################
5
5
6 . /etc/rc.conf
6 . /etc/rc.conf
7 . /etc/rc.d/functions
7 . /etc/rc.d/functions
8
8
9 DAEMON=kallithea
9 DAEMON=kallithea
10 APP_HOMEDIR="/srv"
10 APP_HOMEDIR="/srv"
11 APP_PATH="$APP_HOMEDIR/$DAEMON"
11 APP_PATH="$APP_HOMEDIR/$DAEMON"
12 CONF_NAME="production.ini"
12 CONF_NAME="production.ini"
13 LOG_FILE="/var/log/$DAEMON.log"
13 LOG_FILE="/var/log/$DAEMON.log"
14 PID_FILE="/run/daemons/$DAEMON"
14 PID_FILE="/run/daemons/$DAEMON"
15 APPL=/usr/bin/paster
15 APPL=/usr/bin/gearbox
16 RUN_AS="*****"
16 RUN_AS="*****"
17
17
18 ARGS="serve --daemon \
18 ARGS="serve --daemon \
19 --user=$RUN_AS \
19 --user=$RUN_AS \
20 --group=$RUN_AS \
20 --group=$RUN_AS \
21 --pid-file=$PID_FILE \
21 --pid-file=$PID_FILE \
22 --log-file=$LOG_FILE \
22 --log-file=$LOG_FILE \
23 $APP_PATH/$CONF_NAME"
23 -c $APP_PATH/$CONF_NAME"
24
24
25 [ -r /etc/conf.d/$DAEMON ] && . /etc/conf.d/$DAEMON
25 [ -r /etc/conf.d/$DAEMON ] && . /etc/conf.d/$DAEMON
26
26
27 if [[ -r $PID_FILE ]]; then
27 if [[ -r $PID_FILE ]]; then
28 read -r PID < "$PID_FILE"
28 read -r PID < "$PID_FILE"
29 if [[ $PID && ! -d /proc/$PID ]]; then
29 if [[ $PID && ! -d /proc/$PID ]]; then
30 unset PID
30 unset PID
31 rm_daemon $DAEMON
31 rm_daemon $DAEMON
32 fi
32 fi
33 fi
33 fi
34
34
35 case "$1" in
35 case "$1" in
36 start)
36 start)
37 stat_busy "Starting $DAEMON"
37 stat_busy "Starting $DAEMON"
38 export HOME=$APP_PATH
38 export HOME=$APP_PATH
39 [ -z "$PID" ] && $APPL $ARGS &>/dev/null
39 [ -z "$PID" ] && $APPL $ARGS &>/dev/null
40 if [ $? = 0 ]; then
40 if [ $? = 0 ]; then
41 add_daemon $DAEMON
41 add_daemon $DAEMON
42 stat_done
42 stat_done
43 else
43 else
44 stat_fail
44 stat_fail
45 exit 1
45 exit 1
46 fi
46 fi
47 ;;
47 ;;
48 stop)
48 stop)
49 stat_busy "Stopping $DAEMON"
49 stat_busy "Stopping $DAEMON"
50 [ -n "$PID" ] && kill $PID &>/dev/null
50 [ -n "$PID" ] && kill $PID &>/dev/null
51 if [ $? = 0 ]; then
51 if [ $? = 0 ]; then
52 rm_daemon $DAEMON
52 rm_daemon $DAEMON
53 stat_done
53 stat_done
54 else
54 else
55 stat_fail
55 stat_fail
56 exit 1
56 exit 1
57 fi
57 fi
58 ;;
58 ;;
59 restart)
59 restart)
60 $0 stop
60 $0 stop
61 sleep 1
61 sleep 1
62 $0 start
62 $0 start
63 ;;
63 ;;
64 status)
64 status)
65 stat_busy "Checking $name status";
65 stat_busy "Checking $name status";
66 ck_status $name
66 ck_status $name
67 ;;
67 ;;
68 *)
68 *)
69 echo "usage: $0 {start|stop|restart|status}"
69 echo "usage: $0 {start|stop|restart|status}"
70 esac
70 esac
@@ -1,90 +1,90 b''
1 #!/bin/sh -e
1 #!/bin/sh -e
2 ########################################
2 ########################################
3 #### THIS IS A DEBIAN INIT.D SCRIPT ####
3 #### THIS IS A DEBIAN INIT.D SCRIPT ####
4 ########################################
4 ########################################
5
5
6 ### BEGIN INIT INFO
6 ### BEGIN INIT INFO
7 # Provides: kallithea
7 # Provides: kallithea
8 # Required-Start: $all
8 # Required-Start: $all
9 # Required-Stop: $all
9 # Required-Stop: $all
10 # Default-Start: 2 3 4 5
10 # Default-Start: 2 3 4 5
11 # Default-Stop: 0 1 6
11 # Default-Stop: 0 1 6
12 # Short-Description: starts instance of kallithea
12 # Short-Description: starts instance of kallithea
13 # Description: starts instance of kallithea using start-stop-daemon
13 # Description: starts instance of kallithea using start-stop-daemon
14 ### END INIT INFO
14 ### END INIT INFO
15
15
16 APP_NAME="kallithea"
16 APP_NAME="kallithea"
17 APP_HOMEDIR="opt"
17 APP_HOMEDIR="opt"
18 APP_PATH="/$APP_HOMEDIR/$APP_NAME"
18 APP_PATH="/$APP_HOMEDIR/$APP_NAME"
19
19
20 CONF_NAME="production.ini"
20 CONF_NAME="production.ini"
21
21
22 PID_PATH="$APP_PATH/$APP_NAME.pid"
22 PID_PATH="$APP_PATH/$APP_NAME.pid"
23 LOG_PATH="$APP_PATH/$APP_NAME.log"
23 LOG_PATH="$APP_PATH/$APP_NAME.log"
24
24
25 PYTHON_PATH="/$APP_HOMEDIR/$APP_NAME-venv"
25 PYTHON_PATH="/$APP_HOMEDIR/$APP_NAME-venv"
26
26
27 RUN_AS="root"
27 RUN_AS="root"
28
28
29 DAEMON="$PYTHON_PATH/bin/paster"
29 DAEMON="$PYTHON_PATH/bin/gearbox"
30
30
31 DAEMON_OPTS="serve --daemon \
31 DAEMON_OPTS="serve --daemon \
32 --user=$RUN_AS \
32 --user=$RUN_AS \
33 --group=$RUN_AS \
33 --group=$RUN_AS \
34 --pid-file=$PID_PATH \
34 --pid-file=$PID_PATH \
35 --log-file=$LOG_PATH $APP_PATH/$CONF_NAME"
35 --log-file=$LOG_PATH -c $APP_PATH/$CONF_NAME"
36
36
37
37
38 start() {
38 start() {
39 echo "Starting $APP_NAME"
39 echo "Starting $APP_NAME"
40 PYTHON_EGG_CACHE="/tmp" start-stop-daemon -d $APP_PATH \
40 PYTHON_EGG_CACHE="/tmp" start-stop-daemon -d $APP_PATH \
41 --start --quiet \
41 --start --quiet \
42 --pidfile $PID_PATH \
42 --pidfile $PID_PATH \
43 --user $RUN_AS \
43 --user $RUN_AS \
44 --exec $DAEMON -- $DAEMON_OPTS
44 --exec $DAEMON -- $DAEMON_OPTS
45 }
45 }
46
46
47 stop() {
47 stop() {
48 echo "Stopping $APP_NAME"
48 echo "Stopping $APP_NAME"
49 start-stop-daemon -d $APP_PATH \
49 start-stop-daemon -d $APP_PATH \
50 --stop --quiet \
50 --stop --quiet \
51 --pidfile $PID_PATH || echo "$APP_NAME - Not running!"
51 --pidfile $PID_PATH || echo "$APP_NAME - Not running!"
52
52
53 if [ -f $PID_PATH ]; then
53 if [ -f $PID_PATH ]; then
54 rm $PID_PATH
54 rm $PID_PATH
55 fi
55 fi
56 }
56 }
57
57
58 status() {
58 status() {
59 echo -n "Checking status of $APP_NAME ... "
59 echo -n "Checking status of $APP_NAME ... "
60 pid=`cat $PID_PATH`
60 pid=`cat $PID_PATH`
61 status=`ps ax | grep $pid | grep -ve grep`
61 status=`ps ax | grep $pid | grep -ve grep`
62 if [ "$?" -eq 0 ]; then
62 if [ "$?" -eq 0 ]; then
63 echo "running"
63 echo "running"
64 else
64 else
65 echo "NOT running"
65 echo "NOT running"
66 fi
66 fi
67 }
67 }
68
68
69 case "$1" in
69 case "$1" in
70 status)
70 status)
71 status
71 status
72 ;;
72 ;;
73 start)
73 start)
74 start
74 start
75 ;;
75 ;;
76 stop)
76 stop)
77 stop
77 stop
78 ;;
78 ;;
79 restart)
79 restart)
80 echo "Restarting $APP_NAME"
80 echo "Restarting $APP_NAME"
81 ### stop ###
81 ### stop ###
82 stop
82 stop
83 wait
83 wait
84 ### start ###
84 ### start ###
85 start
85 start
86 ;;
86 ;;
87 *)
87 *)
88 echo "Usage: $0 {start|stop|restart}"
88 echo "Usage: $0 {start|stop|restart}"
89 exit 1
89 exit 1
90 esac
90 esac
@@ -1,61 +1,61 b''
1 #!/sbin/runscript
1 #!/sbin/runscript
2 ########################################
2 ########################################
3 #### THIS IS AN GENTOO INIT.D SCRIPT####
3 #### THIS IS AN GENTOO INIT.D SCRIPT####
4 ########################################
4 ########################################
5
5
6 APP_NAME="kallithea"
6 APP_NAME="kallithea"
7 APP_HOMEDIR="username/python_workspace"
7 APP_HOMEDIR="username/python_workspace"
8 APP_PATH="/home/$APP_HOMEDIR/$APP_NAME"
8 APP_PATH="/home/$APP_HOMEDIR/$APP_NAME"
9
9
10 CONF_NAME="production.ini"
10 CONF_NAME="production.ini"
11
11
12 PID_PATH="$APP_PATH/$APP_NAME.pid"
12 PID_PATH="$APP_PATH/$APP_NAME.pid"
13 LOG_PATH="$APP_PATH/$APP_NAME.log"
13 LOG_PATH="$APP_PATH/$APP_NAME.log"
14
14
15 PYTHON_PATH="/home/$APP_HOMEDIR/v-env"
15 PYTHON_PATH="/home/$APP_HOMEDIR/v-env"
16
16
17 RUN_AS="username"
17 RUN_AS="username"
18
18
19 DAEMON="$PYTHON_PATH/bin/paster"
19 DAEMON="$PYTHON_PATH/bin/gearbox"
20
20
21 DAEMON_OPTS="serve --daemon \
21 DAEMON_OPTS="serve --daemon \
22 --user=$RUN_AS \
22 --user=$RUN_AS \
23 --group=$RUN_AS \
23 --group=$RUN_AS \
24 --pid-file=$PID_PATH \
24 --pid-file=$PID_PATH \
25 --log-file=$LOG_PATH $APP_PATH/$CONF_NAME"
25 --log-file=$LOG_PATH -c $APP_PATH/$CONF_NAME"
26
26
27 #extra options
27 #extra options
28 opts="${opts} restartdelay"
28 opts="${opts} restartdelay"
29
29
30 depend() {
30 depend() {
31 need nginx
31 need nginx
32 }
32 }
33
33
34 start() {
34 start() {
35 ebegin "Starting $APP_NAME"
35 ebegin "Starting $APP_NAME"
36 start-stop-daemon -d $APP_PATH -e PYTHON_EGG_CACHE="/tmp" \
36 start-stop-daemon -d $APP_PATH -e PYTHON_EGG_CACHE="/tmp" \
37 --start --quiet \
37 --start --quiet \
38 --pidfile $PID_PATH \
38 --pidfile $PID_PATH \
39 --user $RUN_AS \
39 --user $RUN_AS \
40 --exec $DAEMON -- $DAEMON_OPTS
40 --exec $DAEMON -- $DAEMON_OPTS
41 eend $?
41 eend $?
42 }
42 }
43
43
44 stop() {
44 stop() {
45 ebegin "Stopping $APP_NAME"
45 ebegin "Stopping $APP_NAME"
46 start-stop-daemon -d $APP_PATH \
46 start-stop-daemon -d $APP_PATH \
47 --stop --quiet \
47 --stop --quiet \
48 --pidfile $PID_PATH || echo "$APP_NAME - Not running!"
48 --pidfile $PID_PATH || echo "$APP_NAME - Not running!"
49 if [ -f $PID_PATH ]; then
49 if [ -f $PID_PATH ]; then
50 rm $PID_PATH
50 rm $PID_PATH
51 fi
51 fi
52 eend $?
52 eend $?
53 }
53 }
54
54
55 restartdelay() {
55 restartdelay() {
56 #stop()
56 #stop()
57 echo "sleep3"
57 echo "sleep3"
58 sleep 3
58 sleep 3
59
59
60 #start()
60 #start()
61 }
61 }
@@ -1,132 +1,132 b''
1 #!/bin/sh
1 #!/bin/sh
2 ########################################
2 ########################################
3 #### THIS IS A REDHAT INIT.D SCRIPT ####
3 #### THIS IS A REDHAT INIT.D SCRIPT ####
4 ########################################
4 ########################################
5
5
6 ##################################################
6 ##################################################
7 #
7 #
8 # Kallithea server startup script
8 # Kallithea server startup script
9 # Recommended default-startup: 2 3 4 5
9 # Recommended default-startup: 2 3 4 5
10 # Recommended default-stop: 0 1 6
10 # Recommended default-stop: 0 1 6
11 #
11 #
12 ##################################################
12 ##################################################
13
13
14
14
15 APP_NAME="kallithea"
15 APP_NAME="kallithea"
16 # the location of your app
16 # the location of your app
17 # since this is a web app, it should go in /var/www
17 # since this is a web app, it should go in /var/www
18 APP_PATH="/var/www/$APP_NAME"
18 APP_PATH="/var/www/$APP_NAME"
19
19
20 CONF_NAME="production.ini"
20 CONF_NAME="production.ini"
21
21
22 # write to wherever the PID should be stored, just ensure
22 # write to wherever the PID should be stored, just ensure
23 # that the user you run paster as has the appropriate permissions
23 # that the user you run gearbox as has the appropriate permissions
24 # same goes for the log file
24 # same goes for the log file
25 PID_PATH="/var/run/kallithea/pid"
25 PID_PATH="/var/run/kallithea/pid"
26 LOG_PATH="/var/log/kallithea/kallithea.log"
26 LOG_PATH="/var/log/kallithea/kallithea.log"
27
27
28 # replace this with the path to the virtual environment you
28 # replace this with the path to the virtual environment you
29 # made for Kallithea
29 # made for Kallithea
30 PYTHON_PATH="/opt/python_virtualenvironments/kallithea-venv"
30 PYTHON_PATH="/opt/python_virtualenvironments/kallithea-venv"
31
31
32 RUN_AS="kallithea"
32 RUN_AS="kallithea"
33
33
34 DAEMON="$PYTHON_PATH/bin/paster"
34 DAEMON="$PYTHON_PATH/bin/gearbox"
35
35
36 DAEMON_OPTS="serve --daemon \
36 DAEMON_OPTS="serve --daemon \
37 --user=$RUN_AS \
37 --user=$RUN_AS \
38 --group=$RUN_AS \
38 --group=$RUN_AS \
39 --pid-file=$PID_PATH \
39 --pid-file=$PID_PATH \
40 --log-file=$LOG_PATH $APP_PATH/$CONF_NAME"
40 --log-file=$LOG_PATH -c $APP_PATH/$CONF_NAME"
41
41
42 DESC="kallithea-server"
42 DESC="kallithea-server"
43 LOCK_FILE="/var/lock/subsys/$APP_NAME"
43 LOCK_FILE="/var/lock/subsys/$APP_NAME"
44
44
45 # source CentOS init functions
45 # source CentOS init functions
46 . /etc/init.d/functions
46 . /etc/init.d/functions
47
47
48 RETVAL=0
48 RETVAL=0
49
49
50 remove_pid () {
50 remove_pid () {
51 rm -f ${PID_PATH}
51 rm -f ${PID_PATH}
52 rmdir `dirname ${PID_PATH}`
52 rmdir `dirname ${PID_PATH}`
53 }
53 }
54
54
55 ensure_pid_dir () {
55 ensure_pid_dir () {
56 PID_DIR=`dirname ${PID_PATH}`
56 PID_DIR=`dirname ${PID_PATH}`
57 if [ ! -d ${PID_DIR} ] ; then
57 if [ ! -d ${PID_DIR} ] ; then
58 mkdir -p ${PID_DIR}
58 mkdir -p ${PID_DIR}
59 chown -R ${RUN_AS}:${RUN_AS} ${PID_DIR}
59 chown -R ${RUN_AS}:${RUN_AS} ${PID_DIR}
60 chmod 755 ${PID_DIR}
60 chmod 755 ${PID_DIR}
61 fi
61 fi
62 }
62 }
63
63
64 start_kallithea () {
64 start_kallithea () {
65 ensure_pid_dir
65 ensure_pid_dir
66 PYTHON_EGG_CACHE="/tmp" daemon --pidfile $PID_PATH \
66 PYTHON_EGG_CACHE="/tmp" daemon --pidfile $PID_PATH \
67 --user $RUN_AS "$DAEMON $DAEMON_OPTS"
67 --user $RUN_AS "$DAEMON $DAEMON_OPTS"
68 RETVAL=$?
68 RETVAL=$?
69 [ $RETVAL -eq 0 ] && touch $LOCK_FILE
69 [ $RETVAL -eq 0 ] && touch $LOCK_FILE
70 return $RETVAL
70 return $RETVAL
71 }
71 }
72
72
73 stop_kallithea () {
73 stop_kallithea () {
74 if [ -e $LOCK_FILE ]; then
74 if [ -e $LOCK_FILE ]; then
75 killproc -p $PID_PATH
75 killproc -p $PID_PATH
76 RETVAL=$?
76 RETVAL=$?
77 rm -f $LOCK_FILE
77 rm -f $LOCK_FILE
78 rm -f $PID_PATH
78 rm -f $PID_PATH
79 else
79 else
80 RETVAL=1
80 RETVAL=1
81 fi
81 fi
82 return $RETVAL
82 return $RETVAL
83 }
83 }
84
84
85 status_kallithea() {
85 status_kallithea() {
86 if [ -e $LOCK_FILE ]; then
86 if [ -e $LOCK_FILE ]; then
87 # exit with non-zero to indicate failure
87 # exit with non-zero to indicate failure
88 RETVAL=1
88 RETVAL=1
89 else
89 else
90 RETVAL=0
90 RETVAL=0
91 fi
91 fi
92 return $RETVAL
92 return $RETVAL
93 }
93 }
94
94
95 restart_kallithea () {
95 restart_kallithea () {
96 stop_kallithea
96 stop_kallithea
97 start_kallithea
97 start_kallithea
98 RETVAL=$?
98 RETVAL=$?
99 }
99 }
100
100
101 case "$1" in
101 case "$1" in
102 start)
102 start)
103 echo -n $"Starting $DESC: "
103 echo -n $"Starting $DESC: "
104 start_kallithea
104 start_kallithea
105 echo
105 echo
106 ;;
106 ;;
107 stop)
107 stop)
108 echo -n $"Stopping $DESC: "
108 echo -n $"Stopping $DESC: "
109 stop_kallithea
109 stop_kallithea
110 echo
110 echo
111 ;;
111 ;;
112 status)
112 status)
113 status_kallithea
113 status_kallithea
114 RETVAL=$?
114 RETVAL=$?
115 if [ ! $RETVAL -eq 0 ]; then
115 if [ ! $RETVAL -eq 0 ]; then
116 echo "Kallithea server is running..."
116 echo "Kallithea server is running..."
117 else
117 else
118 echo "Kallithea server is stopped."
118 echo "Kallithea server is stopped."
119 fi
119 fi
120 ;;
120 ;;
121 restart)
121 restart)
122 echo -n $"Restarting $DESC: "
122 echo -n $"Restarting $DESC: "
123 restart_kallithea
123 restart_kallithea
124 echo
124 echo
125 ;;
125 ;;
126 *)
126 *)
127 echo $"Usage: $0 {start|stop|restart|status}"
127 echo $"Usage: $0 {start|stop|restart|status}"
128 RETVAL=1
128 RETVAL=1
129 ;;
129 ;;
130 esac
130 esac
131
131
132 exit $RETVAL
132 exit $RETVAL
@@ -1,26 +1,26 b''
1 # kallithea - run the kallithea daemon as an upstart job
1 # kallithea - run the kallithea daemon as an upstart job
2 # Change variables/paths as necessary and place file /etc/init/kallithea.conf
2 # Change variables/paths as necessary and place file /etc/init/kallithea.conf
3 # start/stop/restart as normal upstart job (ie: $ start kallithea)
3 # start/stop/restart as normal upstart job (ie: $ start kallithea)
4
4
5 description "Kallithea Mercurial Server"
5 description "Kallithea Mercurial Server"
6 author "Matt Zuba <matt.zuba@goodwillaz.org"
6 author "Matt Zuba <matt.zuba@goodwillaz.org"
7
7
8 start on (local-filesystems and runlevel [2345])
8 start on (local-filesystems and runlevel [2345])
9 stop on runlevel [!2345]
9 stop on runlevel [!2345]
10
10
11 respawn
11 respawn
12
12
13 umask 0022
13 umask 0022
14
14
15 env PIDFILE=/var/hg/kallithea/kallithea.pid
15 env PIDFILE=/var/hg/kallithea/kallithea.pid
16 env LOGFILE=/var/hg/kallithea/log/kallithea.log
16 env LOGFILE=/var/hg/kallithea/log/kallithea.log
17 env APPINI=/var/hg/kallithea/production.ini
17 env APPINI=/var/hg/kallithea/production.ini
18 env HOME=/var/hg
18 env HOME=/var/hg
19 env USER=hg
19 env USER=hg
20 env GROUP=hg
20 env GROUP=hg
21
21
22 exec /var/hg/.virtualenvs/kallithea/bin/paster serve --user=$USER --group=$GROUP --pid-file=$PIDFILE --log-file=$LOGFILE $APPINI
22 exec /var/hg/.virtualenvs/kallithea/bin/gearbox serve --user=$USER --group=$GROUP --pid-file=$PIDFILE --log-file=$LOGFILE -c $APPINI
23
23
24 post-stop script
24 post-stop script
25 rm -f $PIDFILE
25 rm -f $PIDFILE
26 end script
26 end script
@@ -1,51 +1,51 b''
1 ; Kallithea Supervisord
1 ; Kallithea Supervisord
2 ; ##########################
2 ; ##########################
3 ; for help see http://supervisord.org/configuration.html
3 ; for help see http://supervisord.org/configuration.html
4 ; ##########################
4 ; ##########################
5
5
6 [inet_http_server] ; inet (TCP) server disabled by default
6 [inet_http_server] ; inet (TCP) server disabled by default
7 port=127.0.0.1:9001 ; (ip_address:port specifier, *:port for all iface)
7 port=127.0.0.1:9001 ; (ip_address:port specifier, *:port for all iface)
8 ;username=user ; (default is no username (open server))
8 ;username=user ; (default is no username (open server))
9 ;password=123 ; (default is no password (open server))
9 ;password=123 ; (default is no password (open server))
10
10
11 [supervisord]
11 [supervisord]
12 logfile=/%(here)s/supervisord_kallithea.log ; (main log file;default $CWD/supervisord.log)
12 logfile=/%(here)s/supervisord_kallithea.log ; (main log file;default $CWD/supervisord.log)
13 logfile_maxbytes=50MB ; (max main logfile bytes b4 rotation;default 50MB)
13 logfile_maxbytes=50MB ; (max main logfile bytes b4 rotation;default 50MB)
14 logfile_backups=10 ; (num of main logfile rotation backups;default 10)
14 logfile_backups=10 ; (num of main logfile rotation backups;default 10)
15 loglevel=info ; (log level;default info; others: debug,warn,trace)
15 loglevel=info ; (log level;default info; others: debug,warn,trace)
16 pidfile=/%(here)s/supervisord_kallithea.pid ; (supervisord pidfile;default supervisord.pid)
16 pidfile=/%(here)s/supervisord_kallithea.pid ; (supervisord pidfile;default supervisord.pid)
17 nodaemon=true ; (start in foreground if true;default false)
17 nodaemon=true ; (start in foreground if true;default false)
18 minfds=1024 ; (min. avail startup file descriptors;default 1024)
18 minfds=1024 ; (min. avail startup file descriptors;default 1024)
19 minprocs=200 ; (min. avail process descriptors;default 200)
19 minprocs=200 ; (min. avail process descriptors;default 200)
20 umask=022 ; (process file creation umask;default 022)
20 umask=022 ; (process file creation umask;default 022)
21 user=username ; (default is current user, required if root)
21 user=username ; (default is current user, required if root)
22 ;identifier=supervisor ; (supervisord identifier, default is 'supervisor')
22 ;identifier=supervisor ; (supervisord identifier, default is 'supervisor')
23 ;directory=/tmp ; (default is not to cd during start)
23 ;directory=/tmp ; (default is not to cd during start)
24 ;nocleanup=true ; (don't clean up tempfiles at start;default false)
24 ;nocleanup=true ; (don't clean up tempfiles at start;default false)
25 ;childlogdir=/tmp ; ('AUTO' child log dir, default $TEMP)
25 ;childlogdir=/tmp ; ('AUTO' child log dir, default $TEMP)
26 environment=HOME=/srv/kallithea ; (key value pairs to add to environment)
26 environment=HOME=/srv/kallithea ; (key value pairs to add to environment)
27 ;strip_ansi=false ; (strip ansi escape codes in logs; def. false)
27 ;strip_ansi=false ; (strip ansi escape codes in logs; def. false)
28
28
29 ; the below section must remain in the config file for RPC
29 ; the below section must remain in the config file for RPC
30 ; (supervisorctl/web interface) to work, additional interfaces may be
30 ; (supervisorctl/web interface) to work, additional interfaces may be
31 ; added by defining them in separate rpcinterface: sections
31 ; added by defining them in separate rpcinterface: sections
32 [rpcinterface:supervisor]
32 [rpcinterface:supervisor]
33 supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
33 supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
34
34
35 [supervisorctl]
35 [supervisorctl]
36 serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket
36 serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket
37 ;username=user ; should be same as http_username if set
37 ;username=user ; should be same as http_username if set
38 ;password=123 ; should be same as http_password if set
38 ;password=123 ; should be same as http_password if set
39 ;prompt=mysupervisor ; cmd line prompt (default "supervisor")
39 ;prompt=mysupervisor ; cmd line prompt (default "supervisor")
40 ;history_file=~/.sc_history ; use readline history if available
40 ;history_file=~/.sc_history ; use readline history if available
41
41
42
42
43 ; restart with supervisorctl restart kallithea:*
43 ; restart with supervisorctl restart kallithea:*
44 [program:kallithea]
44 [program:kallithea]
45 numprocs = 1
45 numprocs = 1
46 numprocs_start = 5000 # possible should match ports
46 numprocs_start = 5000 # possible should match ports
47 directory=/srv/kallithea
47 directory=/srv/kallithea
48 command = /srv/kallithea/venv/bin/paster serve my.ini
48 command = /srv/kallithea/venv/bin/gearbox serve -c my.ini
49 process_name = %(program_name)s_%(process_num)04d
49 process_name = %(program_name)s_%(process_num)04d
50 redirect_stderr=true
50 redirect_stderr=true
51 stdout_logfile=/%(here)s/kallithea.log
51 stdout_logfile=/%(here)s/kallithea.log
@@ -1,105 +1,105 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14
14
15 # Alembic migration environment (configuration).
15 # Alembic migration environment (configuration).
16
16
17 import logging
17 import logging
18 from logging.config import fileConfig
18 from logging.config import fileConfig
19
19
20 from alembic import context
20 from alembic import context
21 from sqlalchemy import engine_from_config, pool
21 from sqlalchemy import engine_from_config, pool
22
22
23 from kallithea.model import db
23 from kallithea.model import db
24
24
25
25
26 # The alembic.config.Config object, which wraps the current .ini file.
26 # The alembic.config.Config object, which wraps the current .ini file.
27 config = context.config
27 config = context.config
28
28
29 # Default to use the main Kallithea database string in [app:main].
29 # Default to use the main Kallithea database string in [app:main].
30 # For advanced uses, this can be overridden by specifying an explicit
30 # For advanced uses, this can be overridden by specifying an explicit
31 # [alembic] sqlalchemy.url.
31 # [alembic] sqlalchemy.url.
32 database_url = (
32 database_url = (
33 config.get_main_option('sqlalchemy.url') or
33 config.get_main_option('sqlalchemy.url') or
34 config.get_section_option('app:main', 'sqlalchemy.url')
34 config.get_section_option('app:main', 'sqlalchemy.url')
35 )
35 )
36
36
37 # Configure default logging for Alembic. (This can be overriden by the
37 # Configure default logging for Alembic. (This can be overriden by the
38 # config file, but usually isn't.)
38 # config file, but usually isn't.)
39 logging.getLogger('alembic').setLevel(logging.INFO)
39 logging.getLogger('alembic').setLevel(logging.INFO)
40
40
41 # Setup Python loggers based on the config file provided to the alembic
41 # Setup Python loggers based on the config file provided to the alembic
42 # command. If we're being invoked via the Alembic API (presumably for
42 # command. If we're being invoked via the Alembic API (presumably for
43 # stamping during "paster setup-db"), config_file_name is not available,
43 # stamping during "gearbox setup-db"), config_file_name is not available,
44 # and loggers are assumed to already have been configured.
44 # and loggers are assumed to already have been configured.
45 if config.config_file_name:
45 if config.config_file_name:
46 fileConfig(config.config_file_name, disable_existing_loggers=False)
46 fileConfig(config.config_file_name, disable_existing_loggers=False)
47
47
48
48
49 def include_in_autogeneration(object, name, type, reflected, compare_to):
49 def include_in_autogeneration(object, name, type, reflected, compare_to):
50 """Filter changes subject to autogeneration of migrations. """
50 """Filter changes subject to autogeneration of migrations. """
51
51
52 # Don't include changes to sqlite_sequence.
52 # Don't include changes to sqlite_sequence.
53 if type == 'table' and name == 'sqlite_sequence':
53 if type == 'table' and name == 'sqlite_sequence':
54 return False
54 return False
55
55
56 return True
56 return True
57
57
58
58
59 def run_migrations_offline():
59 def run_migrations_offline():
60 """Run migrations in 'offline' (--sql) mode.
60 """Run migrations in 'offline' (--sql) mode.
61
61
62 This produces an SQL script instead of directly applying the changes.
62 This produces an SQL script instead of directly applying the changes.
63 Some migrations may not run in offline mode.
63 Some migrations may not run in offline mode.
64 """
64 """
65 context.configure(
65 context.configure(
66 url=database_url,
66 url=database_url,
67 literal_binds=True,
67 literal_binds=True,
68 )
68 )
69
69
70 with context.begin_transaction():
70 with context.begin_transaction():
71 context.run_migrations()
71 context.run_migrations()
72
72
73
73
74 def run_migrations_online():
74 def run_migrations_online():
75 """Run migrations in 'online' mode.
75 """Run migrations in 'online' mode.
76
76
77 Connects to the database and directly applies the necessary
77 Connects to the database and directly applies the necessary
78 migrations.
78 migrations.
79 """
79 """
80 cfg = config.get_section(config.config_ini_section)
80 cfg = config.get_section(config.config_ini_section)
81 cfg['sqlalchemy.url'] = database_url
81 cfg['sqlalchemy.url'] = database_url
82 connectable = engine_from_config(
82 connectable = engine_from_config(
83 cfg,
83 cfg,
84 prefix='sqlalchemy.',
84 prefix='sqlalchemy.',
85 poolclass=pool.NullPool)
85 poolclass=pool.NullPool)
86
86
87 with connectable.connect() as connection:
87 with connectable.connect() as connection:
88 context.configure(
88 context.configure(
89 connection=connection,
89 connection=connection,
90
90
91 # Support autogeneration of migration scripts based on "diff" between
91 # Support autogeneration of migration scripts based on "diff" between
92 # current database schema and kallithea.model.db schema.
92 # current database schema and kallithea.model.db schema.
93 target_metadata=db.Base.metadata,
93 target_metadata=db.Base.metadata,
94 include_object=include_in_autogeneration,
94 include_object=include_in_autogeneration,
95 render_as_batch=True, # batch mode is needed for SQLite support
95 render_as_batch=True, # batch mode is needed for SQLite support
96 )
96 )
97
97
98 with context.begin_transaction():
98 with context.begin_transaction():
99 context.run_migrations()
99 context.run_migrations()
100
100
101
101
102 if context.is_offline_mode():
102 if context.is_offline_mode():
103 run_migrations_offline()
103 run_migrations_offline()
104 else:
104 else:
105 run_migrations_online()
105 run_migrations_online()
@@ -1,600 +1,610 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%text>################################################################################</%text>
2 <%text>################################################################################</%text>
3 <%text>################################################################################</%text>
3 <%text>################################################################################</%text>
4 # Kallithea - config file generated with kallithea-config #
4 # Kallithea - config file generated with kallithea-config #
5 <%text>################################################################################</%text>
5 <%text>################################################################################</%text>
6 <%text>################################################################################</%text>
6 <%text>################################################################################</%text>
7
7
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10 pdebug = false
10 pdebug = false
11
11
12 <%text>################################################################################</%text>
12 <%text>################################################################################</%text>
13 <%text>## Email settings ##</%text>
13 <%text>## Email settings ##</%text>
14 <%text>## ##</%text>
14 <%text>## ##</%text>
15 <%text>## Refer to the documentation ("Email settings") for more details. ##</%text>
15 <%text>## Refer to the documentation ("Email settings") for more details. ##</%text>
16 <%text>## ##</%text>
16 <%text>## ##</%text>
17 <%text>## It is recommended to use a valid sender address that passes access ##</%text>
17 <%text>## It is recommended to use a valid sender address that passes access ##</%text>
18 <%text>## validation and spam filtering in mail servers. ##</%text>
18 <%text>## validation and spam filtering in mail servers. ##</%text>
19 <%text>################################################################################</%text>
19 <%text>################################################################################</%text>
20
20
21 <%text>## 'From' header for application emails. You can optionally add a name.</%text>
21 <%text>## 'From' header for application emails. You can optionally add a name.</%text>
22 <%text>## Default:</%text>
22 <%text>## Default:</%text>
23 #app_email_from = Kallithea
23 #app_email_from = Kallithea
24 <%text>## Examples:</%text>
24 <%text>## Examples:</%text>
25 #app_email_from = Kallithea <kallithea-noreply@example.com>
25 #app_email_from = Kallithea <kallithea-noreply@example.com>
26 #app_email_from = kallithea-noreply@example.com
26 #app_email_from = kallithea-noreply@example.com
27
27
28 <%text>## Subject prefix for application emails.</%text>
28 <%text>## Subject prefix for application emails.</%text>
29 <%text>## A space between this prefix and the real subject is automatically added.</%text>
29 <%text>## A space between this prefix and the real subject is automatically added.</%text>
30 <%text>## Default:</%text>
30 <%text>## Default:</%text>
31 #email_prefix =
31 #email_prefix =
32 <%text>## Example:</%text>
32 <%text>## Example:</%text>
33 #email_prefix = [Kallithea]
33 #email_prefix = [Kallithea]
34
34
35 <%text>## Recipients for error emails and fallback recipients of application mails.</%text>
35 <%text>## Recipients for error emails and fallback recipients of application mails.</%text>
36 <%text>## Multiple addresses can be specified, space-separated.</%text>
36 <%text>## Multiple addresses can be specified, space-separated.</%text>
37 <%text>## Only addresses are allowed, do not add any name part.</%text>
37 <%text>## Only addresses are allowed, do not add any name part.</%text>
38 <%text>## Default:</%text>
38 <%text>## Default:</%text>
39 #email_to =
39 #email_to =
40 <%text>## Examples:</%text>
40 <%text>## Examples:</%text>
41 #email_to = admin@example.com
41 #email_to = admin@example.com
42 #email_to = admin@example.com another_admin@example.com
42 #email_to = admin@example.com another_admin@example.com
43
43
44 <%text>## 'From' header for error emails. You can optionally add a name.</%text>
44 <%text>## 'From' header for error emails. You can optionally add a name.</%text>
45 <%text>## Default:</%text>
45 <%text>## Default:</%text>
46 #error_email_from = pylons@yourapp.com
46 #error_email_from = pylons@yourapp.com
47 <%text>## Examples:</%text>
47 <%text>## Examples:</%text>
48 #error_email_from = Kallithea Errors <kallithea-noreply@example.com>
48 #error_email_from = Kallithea Errors <kallithea-noreply@example.com>
49 #error_email_from = paste_error@example.com
49 #error_email_from = paste_error@example.com
50
50
51 <%text>## SMTP server settings</%text>
51 <%text>## SMTP server settings</%text>
52 <%text>## If specifying credentials, make sure to use secure connections.</%text>
52 <%text>## If specifying credentials, make sure to use secure connections.</%text>
53 <%text>## Default: Send unencrypted unauthenticated mails to the specified smtp_server.</%text>
53 <%text>## Default: Send unencrypted unauthenticated mails to the specified smtp_server.</%text>
54 <%text>## For "SSL", use smtp_use_ssl = true and smtp_port = 465.</%text>
54 <%text>## For "SSL", use smtp_use_ssl = true and smtp_port = 465.</%text>
55 <%text>## For "STARTTLS", use smtp_use_tls = true and smtp_port = 587.</%text>
55 <%text>## For "STARTTLS", use smtp_use_tls = true and smtp_port = 587.</%text>
56 #smtp_server = smtp.example.com
56 #smtp_server = smtp.example.com
57 #smtp_username =
57 #smtp_username =
58 #smtp_password =
58 #smtp_password =
59 #smtp_port = 25
59 #smtp_port = 25
60 #smtp_use_ssl = false
60 #smtp_use_ssl = false
61 #smtp_use_tls = false
61 #smtp_use_tls = false
62
62
63 [server:main]
63 [server:main]
64 %if http_server == 'paste':
64 %if http_server == 'gearbox':
65 <%text>## PASTE ##</%text>
65 <%text>## Gearbox default web server ##</%text>
66 use = egg:Paste#http
66 use = egg:gearbox#wsgiref
67 <%text>## nr of worker threads to spawn</%text>
67 <%text>## nr of worker threads to spawn</%text>
68 threadpool_workers = 1
68 threadpool_workers = 1
69 <%text>## max request before thread respawn</%text>
69 <%text>## max request before thread respawn</%text>
70 threadpool_max_requests = 100
70 threadpool_max_requests = 100
71 <%text>## option to use threads of process</%text>
71 <%text>## option to use threads of process</%text>
72 use_threadpool = true
72 use_threadpool = true
73
73
74 %elif http_server == 'gevent':
75 <%text>## Gearbox gevent web server ##</%text>
76 use = egg:gearbox#gevent
77
74 %elif http_server == 'waitress':
78 %elif http_server == 'waitress':
75 <%text>## WAITRESS ##</%text>
79 <%text>## WAITRESS ##</%text>
76 use = egg:waitress#main
80 use = egg:waitress#main
77 <%text>## number of worker threads</%text>
81 <%text>## number of worker threads</%text>
78 threads = 1
82 threads = 1
79 <%text>## MAX BODY SIZE 100GB</%text>
83 <%text>## MAX BODY SIZE 100GB</%text>
80 max_request_body_size = 107374182400
84 max_request_body_size = 107374182400
81 <%text>## use poll instead of select, fixes fd limits, may not work on old</%text>
85 <%text>## use poll instead of select, fixes fd limits, may not work on old</%text>
82 <%text>## windows systems.</%text>
86 <%text>## windows systems.</%text>
83 #asyncore_use_poll = True
87 #asyncore_use_poll = True
84
88
85 %elif http_server == 'gunicorn':
89 %elif http_server == 'gunicorn':
86 <%text>## GUNICORN ##</%text>
90 <%text>## GUNICORN ##</%text>
87 use = egg:gunicorn#main
91 use = egg:gunicorn#main
88 <%text>## number of process workers. You must set `instance_id = *` when this option</%text>
92 <%text>## number of process workers. You must set `instance_id = *` when this option</%text>
89 <%text>## is set to more than one worker</%text>
93 <%text>## is set to more than one worker</%text>
90 workers = 1
94 workers = 1
91 <%text>## process name</%text>
95 <%text>## process name</%text>
92 proc_name = kallithea
96 proc_name = kallithea
93 <%text>## type of worker class, one of sync, eventlet, gevent, tornado</%text>
97 <%text>## type of worker class, one of sync, eventlet, gevent, tornado</%text>
94 <%text>## recommended for bigger setup is using of of other than sync one</%text>
98 <%text>## recommended for bigger setup is using of of other than sync one</%text>
95 worker_class = sync
99 worker_class = sync
96 max_requests = 1000
100 max_requests = 1000
97 <%text>## amount of time a worker can handle request before it gets killed and</%text>
101 <%text>## amount of time a worker can handle request before it gets killed and</%text>
98 <%text>## restarted</%text>
102 <%text>## restarted</%text>
99 timeout = 3600
103 timeout = 3600
100
104
101 %elif http_server == 'uwsgi':
105 %elif http_server == 'uwsgi':
102 <%text>## UWSGI ##</%text>
106 <%text>## UWSGI ##</%text>
103 <%text>## run with uwsgi --ini-paste-logged <inifile.ini></%text>
107 <%text>## run with uwsgi --ini-paste-logged <inifile.ini></%text>
104 [uwsgi]
108 [uwsgi]
105 socket = /tmp/uwsgi.sock
109 socket = /tmp/uwsgi.sock
106 master = true
110 master = true
107 http = 127.0.0.1:5000
111 http = 127.0.0.1:5000
108
112
109 <%text>## set as deamon and redirect all output to file</%text>
113 <%text>## set as deamon and redirect all output to file</%text>
110 #daemonize = ./uwsgi_kallithea.log
114 #daemonize = ./uwsgi_kallithea.log
111
115
112 <%text>## master process PID</%text>
116 <%text>## master process PID</%text>
113 pidfile = ./uwsgi_kallithea.pid
117 pidfile = ./uwsgi_kallithea.pid
114
118
115 <%text>## stats server with workers statistics, use uwsgitop</%text>
119 <%text>## stats server with workers statistics, use uwsgitop</%text>
116 <%text>## for monitoring, `uwsgitop 127.0.0.1:1717`</%text>
120 <%text>## for monitoring, `uwsgitop 127.0.0.1:1717`</%text>
117 stats = 127.0.0.1:1717
121 stats = 127.0.0.1:1717
118 memory-report = true
122 memory-report = true
119
123
120 <%text>## log 5XX errors</%text>
124 <%text>## log 5XX errors</%text>
121 log-5xx = true
125 log-5xx = true
122
126
123 <%text>## Set the socket listen queue size.</%text>
127 <%text>## Set the socket listen queue size.</%text>
124 listen = 256
128 listen = 256
125
129
126 <%text>## Gracefully Reload workers after the specified amount of managed requests</%text>
130 <%text>## Gracefully Reload workers after the specified amount of managed requests</%text>
127 <%text>## (avoid memory leaks).</%text>
131 <%text>## (avoid memory leaks).</%text>
128 max-requests = 1000
132 max-requests = 1000
129
133
130 <%text>## enable large buffers</%text>
134 <%text>## enable large buffers</%text>
131 buffer-size = 65535
135 buffer-size = 65535
132
136
133 <%text>## socket and http timeouts ##</%text>
137 <%text>## socket and http timeouts ##</%text>
134 http-timeout = 3600
138 http-timeout = 3600
135 socket-timeout = 3600
139 socket-timeout = 3600
136
140
137 <%text>## Log requests slower than the specified number of milliseconds.</%text>
141 <%text>## Log requests slower than the specified number of milliseconds.</%text>
138 log-slow = 10
142 log-slow = 10
139
143
140 <%text>## Exit if no app can be loaded.</%text>
144 <%text>## Exit if no app can be loaded.</%text>
141 need-app = true
145 need-app = true
142
146
143 <%text>## Set lazy mode (load apps in workers instead of master).</%text>
147 <%text>## Set lazy mode (load apps in workers instead of master).</%text>
144 lazy = true
148 lazy = true
145
149
146 <%text>## scaling ##</%text>
150 <%text>## scaling ##</%text>
147 <%text>## set cheaper algorithm to use, if not set default will be used</%text>
151 <%text>## set cheaper algorithm to use, if not set default will be used</%text>
148 cheaper-algo = spare
152 cheaper-algo = spare
149
153
150 <%text>## minimum number of workers to keep at all times</%text>
154 <%text>## minimum number of workers to keep at all times</%text>
151 cheaper = 1
155 cheaper = 1
152
156
153 <%text>## number of workers to spawn at startup</%text>
157 <%text>## number of workers to spawn at startup</%text>
154 cheaper-initial = 1
158 cheaper-initial = 1
155
159
156 <%text>## maximum number of workers that can be spawned</%text>
160 <%text>## maximum number of workers that can be spawned</%text>
157 workers = 4
161 workers = 4
158
162
159 <%text>## how many workers should be spawned at a time</%text>
163 <%text>## how many workers should be spawned at a time</%text>
160 cheaper-step = 1
164 cheaper-step = 1
161
165
162 %endif
166 %endif
163 <%text>## COMMON ##</%text>
167 <%text>## COMMON ##</%text>
164 host = ${host}
168 host = ${host}
165 port = ${port}
169 port = ${port}
166
170
167 <%text>## middleware for hosting the WSGI application under a URL prefix</%text>
171 <%text>## middleware for hosting the WSGI application under a URL prefix</%text>
168 #[filter:proxy-prefix]
172 #[filter:proxy-prefix]
169 #use = egg:PasteDeploy#prefix
173 #use = egg:PasteDeploy#prefix
170 #prefix = /<your-prefix>
174 #prefix = /<your-prefix>
171
175
172 [app:main]
176 [app:main]
173 use = egg:kallithea
177 use = egg:kallithea
174 <%text>## enable proxy prefix middleware</%text>
178 <%text>## enable proxy prefix middleware</%text>
175 #filter-with = proxy-prefix
179 #filter-with = proxy-prefix
176
180
177 full_stack = true
181 full_stack = true
178 static_files = true
182 static_files = true
179 <%text>## Available Languages:</%text>
183 <%text>## Available Languages:</%text>
180 <%text>## cs de fr hu ja nl_BE pl pt_BR ru sk zh_CN zh_TW</%text>
184 <%text>## cs de fr hu ja nl_BE pl pt_BR ru sk zh_CN zh_TW</%text>
181 lang =
185 lang =
182 cache_dir = ${here}/data
186 cache_dir = ${here}/data
183 index_dir = ${here}/data/index
187 index_dir = ${here}/data/index
184
188
185 <%text>## perform a full repository scan on each server start, this should be</%text>
189 <%text>## perform a full repository scan on each server start, this should be</%text>
186 <%text>## set to false after first startup, to allow faster server restarts.</%text>
190 <%text>## set to false after first startup, to allow faster server restarts.</%text>
187 initial_repo_scan = false
191 initial_repo_scan = false
188
192
189 <%text>## uncomment and set this path to use archive download cache</%text>
193 <%text>## uncomment and set this path to use archive download cache</%text>
190 archive_cache_dir = ${here}/tarballcache
194 archive_cache_dir = ${here}/tarballcache
191
195
192 <%text>## change this to unique ID for security</%text>
196 <%text>## change this to unique ID for security</%text>
193 app_instance_uuid = ${uuid()}
197 app_instance_uuid = ${uuid()}
194
198
195 <%text>## cut off limit for large diffs (size in bytes)</%text>
199 <%text>## cut off limit for large diffs (size in bytes)</%text>
196 cut_off_limit = 256000
200 cut_off_limit = 256000
197
201
198 <%text>## force https in Kallithea, fixes https redirects, assumes it's always https</%text>
202 <%text>## force https in Kallithea, fixes https redirects, assumes it's always https</%text>
199 force_https = false
203 force_https = false
200
204
201 <%text>## use Strict-Transport-Security headers</%text>
205 <%text>## use Strict-Transport-Security headers</%text>
202 use_htsts = false
206 use_htsts = false
203
207
204 <%text>## number of commits stats will parse on each iteration</%text>
208 <%text>## number of commits stats will parse on each iteration</%text>
205 commit_parse_limit = 25
209 commit_parse_limit = 25
206
210
207 <%text>## path to git executable</%text>
211 <%text>## path to git executable</%text>
208 git_path = git
212 git_path = git
209
213
210 <%text>## git rev filter option, --all is the default filter, if you need to</%text>
214 <%text>## git rev filter option, --all is the default filter, if you need to</%text>
211 <%text>## hide all refs in changelog switch this to --branches --tags</%text>
215 <%text>## hide all refs in changelog switch this to --branches --tags</%text>
212 #git_rev_filter = --branches --tags
216 #git_rev_filter = --branches --tags
213
217
214 <%text>## RSS feed options</%text>
218 <%text>## RSS feed options</%text>
215 rss_cut_off_limit = 256000
219 rss_cut_off_limit = 256000
216 rss_items_per_page = 10
220 rss_items_per_page = 10
217 rss_include_diff = false
221 rss_include_diff = false
218
222
219 <%text>## options for showing and identifying changesets</%text>
223 <%text>## options for showing and identifying changesets</%text>
220 show_sha_length = 12
224 show_sha_length = 12
221 show_revision_number = false
225 show_revision_number = false
222
226
223 <%text>## Canonical URL to use when creating full URLs in UI and texts.</%text>
227 <%text>## Canonical URL to use when creating full URLs in UI and texts.</%text>
224 <%text>## Useful when the site is available under different names or protocols.</%text>
228 <%text>## Useful when the site is available under different names or protocols.</%text>
225 <%text>## Defaults to what is provided in the WSGI environment.</%text>
229 <%text>## Defaults to what is provided in the WSGI environment.</%text>
226 #canonical_url = https://kallithea.example.com/repos
230 #canonical_url = https://kallithea.example.com/repos
227
231
228 <%text>## gist URL alias, used to create nicer urls for gist. This should be an</%text>
232 <%text>## gist URL alias, used to create nicer urls for gist. This should be an</%text>
229 <%text>## url that does rewrites to _admin/gists/<gistid>.</%text>
233 <%text>## url that does rewrites to _admin/gists/<gistid>.</%text>
230 <%text>## example: http://gist.example.com/{gistid}. Empty means use the internal</%text>
234 <%text>## example: http://gist.example.com/{gistid}. Empty means use the internal</%text>
231 <%text>## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid></%text>
235 <%text>## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid></%text>
232 gist_alias_url =
236 gist_alias_url =
233
237
234 <%text>## white list of API enabled controllers. This allows to add list of</%text>
238 <%text>## white list of API enabled controllers. This allows to add list of</%text>
235 <%text>## controllers to which access will be enabled by api_key. eg: to enable</%text>
239 <%text>## controllers to which access will be enabled by api_key. eg: to enable</%text>
236 <%text>## api access to raw_files put `FilesController:raw`, to enable access to patches</%text>
240 <%text>## api access to raw_files put `FilesController:raw`, to enable access to patches</%text>
237 <%text>## add `ChangesetController:changeset_patch`. This list should be "," separated</%text>
241 <%text>## add `ChangesetController:changeset_patch`. This list should be "," separated</%text>
238 <%text>## Syntax is <ControllerClass>:<function>. Check debug logs for generated names</%text>
242 <%text>## Syntax is <ControllerClass>:<function>. Check debug logs for generated names</%text>
239 <%text>## Recommended settings below are commented out:</%text>
243 <%text>## Recommended settings below are commented out:</%text>
240 api_access_controllers_whitelist =
244 api_access_controllers_whitelist =
241 # ChangesetController:changeset_patch,
245 # ChangesetController:changeset_patch,
242 # ChangesetController:changeset_raw,
246 # ChangesetController:changeset_raw,
243 # FilesController:raw,
247 # FilesController:raw,
244 # FilesController:archivefile
248 # FilesController:archivefile
245
249
246 <%text>## default encoding used to convert from and to unicode</%text>
250 <%text>## default encoding used to convert from and to unicode</%text>
247 <%text>## can be also a comma separated list of encoding in case of mixed encodings</%text>
251 <%text>## can be also a comma separated list of encoding in case of mixed encodings</%text>
248 default_encoding = utf8
252 default_encoding = utf8
249
253
250 <%text>## issue tracker for Kallithea (leave blank to disable, absent for default)</%text>
254 <%text>## issue tracker for Kallithea (leave blank to disable, absent for default)</%text>
251 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
255 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
252
256
253 <%text>## issue tracking mapping for commits messages</%text>
257 <%text>## issue tracking mapping for commits messages</%text>
254 <%text>## comment out issue_pat, issue_server, issue_prefix to enable</%text>
258 <%text>## comment out issue_pat, issue_server, issue_prefix to enable</%text>
255
259
256 <%text>## pattern to get the issues from commit messages</%text>
260 <%text>## pattern to get the issues from commit messages</%text>
257 <%text>## default one used here is #<numbers> with a regex passive group for `#`</%text>
261 <%text>## default one used here is #<numbers> with a regex passive group for `#`</%text>
258 <%text>## {id} will be all groups matched from this pattern</%text>
262 <%text>## {id} will be all groups matched from this pattern</%text>
259
263
260 issue_pat = (?:\s*#)(\d+)
264 issue_pat = (?:\s*#)(\d+)
261
265
262 <%text>## server url to the issue, each {id} will be replaced with match</%text>
266 <%text>## server url to the issue, each {id} will be replaced with match</%text>
263 <%text>## fetched from the regex and {repo} is replaced with full repository name</%text>
267 <%text>## fetched from the regex and {repo} is replaced with full repository name</%text>
264 <%text>## including groups {repo_name} is replaced with just name of repo</%text>
268 <%text>## including groups {repo_name} is replaced with just name of repo</%text>
265
269
266 issue_server_link = https://issues.example.com/{repo}/issue/{id}
270 issue_server_link = https://issues.example.com/{repo}/issue/{id}
267
271
268 <%text>## prefix to add to link to indicate it's an url</%text>
272 <%text>## prefix to add to link to indicate it's an url</%text>
269 <%text>## #314 will be replaced by <issue_prefix><id></%text>
273 <%text>## #314 will be replaced by <issue_prefix><id></%text>
270
274
271 issue_prefix = #
275 issue_prefix = #
272
276
273 <%text>## issue_pat, issue_server_link, issue_prefix can have suffixes to specify</%text>
277 <%text>## issue_pat, issue_server_link, issue_prefix can have suffixes to specify</%text>
274 <%text>## multiple patterns, to other issues server, wiki or others</%text>
278 <%text>## multiple patterns, to other issues server, wiki or others</%text>
275 <%text>## below an example how to create a wiki pattern</%text>
279 <%text>## below an example how to create a wiki pattern</%text>
276 # wiki-some-id -> https://wiki.example.com/some-id
280 # wiki-some-id -> https://wiki.example.com/some-id
277
281
278 #issue_pat_wiki = (?:wiki-)(.+)
282 #issue_pat_wiki = (?:wiki-)(.+)
279 #issue_server_link_wiki = https://wiki.example.com/{id}
283 #issue_server_link_wiki = https://wiki.example.com/{id}
280 #issue_prefix_wiki = WIKI-
284 #issue_prefix_wiki = WIKI-
281
285
282 <%text>## alternative return HTTP header for failed authentication. Default HTTP</%text>
286 <%text>## alternative return HTTP header for failed authentication. Default HTTP</%text>
283 <%text>## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with</%text>
287 <%text>## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with</%text>
284 <%text>## handling that. Set this variable to 403 to return HTTPForbidden</%text>
288 <%text>## handling that. Set this variable to 403 to return HTTPForbidden</%text>
285 auth_ret_code =
289 auth_ret_code =
286
290
287 <%text>## locking return code. When repository is locked return this HTTP code. 2XX</%text>
291 <%text>## locking return code. When repository is locked return this HTTP code. 2XX</%text>
288 <%text>## codes don't break the transactions while 4XX codes do</%text>
292 <%text>## codes don't break the transactions while 4XX codes do</%text>
289 lock_ret_code = 423
293 lock_ret_code = 423
290
294
291 <%text>## allows to change the repository location in settings page</%text>
295 <%text>## allows to change the repository location in settings page</%text>
292 allow_repo_location_change = True
296 allow_repo_location_change = True
293
297
294 <%text>## allows to setup custom hooks in settings page</%text>
298 <%text>## allows to setup custom hooks in settings page</%text>
295 allow_custom_hooks_settings = True
299 allow_custom_hooks_settings = True
296
300
297 <%text>## extra extensions for indexing, space separated and without the leading '.'.</%text>
301 <%text>## extra extensions for indexing, space separated and without the leading '.'.</%text>
298 # index.extensions =
302 # index.extensions =
299 # gemfile
303 # gemfile
300 # lock
304 # lock
301
305
302 <%text>## extra filenames for indexing, space separated</%text>
306 <%text>## extra filenames for indexing, space separated</%text>
303 # index.filenames =
307 # index.filenames =
304 # .dockerignore
308 # .dockerignore
305 # .editorconfig
309 # .editorconfig
306 # INSTALL
310 # INSTALL
307 # CHANGELOG
311 # CHANGELOG
308
312
309 <%text>####################################</%text>
313 <%text>####################################</%text>
310 <%text>### CELERY CONFIG ####</%text>
314 <%text>### CELERY CONFIG ####</%text>
311 <%text>####################################</%text>
315 <%text>####################################</%text>
312
316
313 use_celery = false
317 use_celery = false
314
318
315 <%text>## Example: connect to the virtual host 'rabbitmqhost' on localhost as rabbitmq:</%text>
319 <%text>## Example: connect to the virtual host 'rabbitmqhost' on localhost as rabbitmq:</%text>
316 broker.url = amqp://rabbitmq:qewqew@localhost:5672/rabbitmqhost
320 broker.url = amqp://rabbitmq:qewqew@localhost:5672/rabbitmqhost
317
321
318 celery.imports = kallithea.lib.celerylib.tasks
322 celery.imports = kallithea.lib.celerylib.tasks
319 celery.accept.content = pickle
323 celery.accept.content = pickle
320 celery.result.backend = amqp
324 celery.result.backend = amqp
321 celery.result.dburi = amqp://
325 celery.result.dburi = amqp://
322 celery.result.serialier = json
326 celery.result.serialier = json
323
327
324 #celery.send.task.error.emails = true
328 #celery.send.task.error.emails = true
325 #celery.amqp.task.result.expires = 18000
329 #celery.amqp.task.result.expires = 18000
326
330
327 celeryd.concurrency = 2
331 celeryd.concurrency = 2
328 celeryd.max.tasks.per.child = 1
332 celeryd.max.tasks.per.child = 1
329
333
330 <%text>## If true, tasks will never be sent to the queue, but executed locally instead.</%text>
334 <%text>## If true, tasks will never be sent to the queue, but executed locally instead.</%text>
331 celery.always.eager = false
335 celery.always.eager = false
332
336
333 <%text>####################################</%text>
337 <%text>####################################</%text>
334 <%text>### BEAKER CACHE ####</%text>
338 <%text>### BEAKER CACHE ####</%text>
335 <%text>####################################</%text>
339 <%text>####################################</%text>
336
340
337 beaker.cache.data_dir = ${here}/data/cache/data
341 beaker.cache.data_dir = ${here}/data/cache/data
338 beaker.cache.lock_dir = ${here}/data/cache/lock
342 beaker.cache.lock_dir = ${here}/data/cache/lock
339
343
340 beaker.cache.regions = short_term,long_term,sql_cache_short
344 beaker.cache.regions = short_term,long_term,sql_cache_short
341
345
342 beaker.cache.short_term.type = memory
346 beaker.cache.short_term.type = memory
343 beaker.cache.short_term.expire = 60
347 beaker.cache.short_term.expire = 60
344 beaker.cache.short_term.key_length = 256
348 beaker.cache.short_term.key_length = 256
345
349
346 beaker.cache.long_term.type = memory
350 beaker.cache.long_term.type = memory
347 beaker.cache.long_term.expire = 36000
351 beaker.cache.long_term.expire = 36000
348 beaker.cache.long_term.key_length = 256
352 beaker.cache.long_term.key_length = 256
349
353
350 beaker.cache.sql_cache_short.type = memory
354 beaker.cache.sql_cache_short.type = memory
351 beaker.cache.sql_cache_short.expire = 10
355 beaker.cache.sql_cache_short.expire = 10
352 beaker.cache.sql_cache_short.key_length = 256
356 beaker.cache.sql_cache_short.key_length = 256
353
357
354 <%text>####################################</%text>
358 <%text>####################################</%text>
355 <%text>### BEAKER SESSION ####</%text>
359 <%text>### BEAKER SESSION ####</%text>
356 <%text>####################################</%text>
360 <%text>####################################</%text>
357
361
358 <%text>## Name of session cookie. Should be unique for a given host and path, even when running</%text>
362 <%text>## Name of session cookie. Should be unique for a given host and path, even when running</%text>
359 <%text>## on different ports. Otherwise, cookie sessions will be shared and messed up.</%text>
363 <%text>## on different ports. Otherwise, cookie sessions will be shared and messed up.</%text>
360 beaker.session.key = kallithea
364 beaker.session.key = kallithea
361 <%text>## Sessions should always only be accessible by the browser, not directly by JavaScript.</%text>
365 <%text>## Sessions should always only be accessible by the browser, not directly by JavaScript.</%text>
362 beaker.session.httponly = true
366 beaker.session.httponly = true
363 <%text>## Session lifetime. 2592000 seconds is 30 days.</%text>
367 <%text>## Session lifetime. 2592000 seconds is 30 days.</%text>
364 beaker.session.timeout = 2592000
368 beaker.session.timeout = 2592000
365
369
366 <%text>## Server secret used with HMAC to ensure integrity of cookies.</%text>
370 <%text>## Server secret used with HMAC to ensure integrity of cookies.</%text>
367 beaker.session.secret = ${uuid()}
371 beaker.session.secret = ${uuid()}
368 <%text>## Further, encrypt the data with AES.</%text>
372 <%text>## Further, encrypt the data with AES.</%text>
369 #beaker.session.encrypt_key = <key_for_encryption>
373 #beaker.session.encrypt_key = <key_for_encryption>
370 #beaker.session.validate_key = <validation_key>
374 #beaker.session.validate_key = <validation_key>
371
375
372 <%text>## Type of storage used for the session, current types are</%text>
376 <%text>## Type of storage used for the session, current types are</%text>
373 <%text>## dbm, file, memcached, database, and memory.</%text>
377 <%text>## dbm, file, memcached, database, and memory.</%text>
374
378
375 <%text>## File system storage of session data. (default)</%text>
379 <%text>## File system storage of session data. (default)</%text>
376 #beaker.session.type = file
380 #beaker.session.type = file
377
381
378 <%text>## Cookie only, store all session data inside the cookie. Requires secure secrets.</%text>
382 <%text>## Cookie only, store all session data inside the cookie. Requires secure secrets.</%text>
379 #beaker.session.type = cookie
383 #beaker.session.type = cookie
380
384
381 <%text>## Database storage of session data.</%text>
385 <%text>## Database storage of session data.</%text>
382 #beaker.session.type = ext:database
386 #beaker.session.type = ext:database
383 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/kallithea
387 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/kallithea
384 #beaker.session.table_name = db_session
388 #beaker.session.table_name = db_session
385
389
386 %if error_aggregation_service == 'appenlight':
390 %if error_aggregation_service == 'appenlight':
387 <%text>############################</%text>
391 <%text>############################</%text>
388 <%text>## ERROR HANDLING SYSTEMS ##</%text>
392 <%text>## ERROR HANDLING SYSTEMS ##</%text>
389 <%text>############################</%text>
393 <%text>############################</%text>
390
394
391 <%text>####################</%text>
395 <%text>####################</%text>
392 <%text>### [appenlight] ###</%text>
396 <%text>### [appenlight] ###</%text>
393 <%text>####################</%text>
397 <%text>####################</%text>
394
398
395 <%text>## AppEnlight is tailored to work with Kallithea, see</%text>
399 <%text>## AppEnlight is tailored to work with Kallithea, see</%text>
396 <%text>## http://appenlight.com for details how to obtain an account</%text>
400 <%text>## http://appenlight.com for details how to obtain an account</%text>
397 <%text>## you must install python package `appenlight_client` to make it work</%text>
401 <%text>## you must install python package `appenlight_client` to make it work</%text>
398
402
399 <%text>## appenlight enabled</%text>
403 <%text>## appenlight enabled</%text>
400 appenlight = false
404 appenlight = false
401
405
402 appenlight.server_url = https://api.appenlight.com
406 appenlight.server_url = https://api.appenlight.com
403 appenlight.api_key = YOUR_API_KEY
407 appenlight.api_key = YOUR_API_KEY
404
408
405 <%text>## TWEAK AMOUNT OF INFO SENT HERE</%text>
409 <%text>## TWEAK AMOUNT OF INFO SENT HERE</%text>
406
410
407 <%text>## enables 404 error logging (default False)</%text>
411 <%text>## enables 404 error logging (default False)</%text>
408 appenlight.report_404 = false
412 appenlight.report_404 = false
409
413
410 <%text>## time in seconds after request is considered being slow (default 1)</%text>
414 <%text>## time in seconds after request is considered being slow (default 1)</%text>
411 appenlight.slow_request_time = 1
415 appenlight.slow_request_time = 1
412
416
413 <%text>## record slow requests in application</%text>
417 <%text>## record slow requests in application</%text>
414 <%text>## (needs to be enabled for slow datastore recording and time tracking)</%text>
418 <%text>## (needs to be enabled for slow datastore recording and time tracking)</%text>
415 appenlight.slow_requests = true
419 appenlight.slow_requests = true
416
420
417 <%text>## enable hooking to application loggers</%text>
421 <%text>## enable hooking to application loggers</%text>
418 #appenlight.logging = true
422 #appenlight.logging = true
419
423
420 <%text>## minimum log level for log capture</%text>
424 <%text>## minimum log level for log capture</%text>
421 #appenlight.logging.level = WARNING
425 #appenlight.logging.level = WARNING
422
426
423 <%text>## send logs only from erroneous/slow requests</%text>
427 <%text>## send logs only from erroneous/slow requests</%text>
424 <%text>## (saves API quota for intensive logging)</%text>
428 <%text>## (saves API quota for intensive logging)</%text>
425 appenlight.logging_on_error = false
429 appenlight.logging_on_error = false
426
430
427 <%text>## list of additional keywords that should be grabbed from environ object</%text>
431 <%text>## list of additional keywords that should be grabbed from environ object</%text>
428 <%text>## can be string with comma separated list of words in lowercase</%text>
432 <%text>## can be string with comma separated list of words in lowercase</%text>
429 <%text>## (by default client will always send following info:</%text>
433 <%text>## (by default client will always send following info:</%text>
430 <%text>## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that</%text>
434 <%text>## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that</%text>
431 <%text>## start with HTTP* this list be extended with additional keywords here</%text>
435 <%text>## start with HTTP* this list be extended with additional keywords here</%text>
432 appenlight.environ_keys_whitelist =
436 appenlight.environ_keys_whitelist =
433
437
434 <%text>## list of keywords that should be blanked from request object</%text>
438 <%text>## list of keywords that should be blanked from request object</%text>
435 <%text>## can be string with comma separated list of words in lowercase</%text>
439 <%text>## can be string with comma separated list of words in lowercase</%text>
436 <%text>## (by default client will always blank keys that contain following words</%text>
440 <%text>## (by default client will always blank keys that contain following words</%text>
437 <%text>## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'</%text>
441 <%text>## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'</%text>
438 <%text>## this list be extended with additional keywords set here</%text>
442 <%text>## this list be extended with additional keywords set here</%text>
439 appenlight.request_keys_blacklist =
443 appenlight.request_keys_blacklist =
440
444
441 <%text>## list of namespaces that should be ignores when gathering log entries</%text>
445 <%text>## list of namespaces that should be ignores when gathering log entries</%text>
442 <%text>## can be string with comma separated list of namespaces</%text>
446 <%text>## can be string with comma separated list of namespaces</%text>
443 <%text>## (by default the client ignores own entries: appenlight_client.client)</%text>
447 <%text>## (by default the client ignores own entries: appenlight_client.client)</%text>
444 appenlight.log_namespace_blacklist =
448 appenlight.log_namespace_blacklist =
445
449
446 %elif error_aggregation_service == 'sentry':
450 %elif error_aggregation_service == 'sentry':
447 <%text>################</%text>
451 <%text>################</%text>
448 <%text>### [sentry] ###</%text>
452 <%text>### [sentry] ###</%text>
449 <%text>################</%text>
453 <%text>################</%text>
450
454
451 <%text>## sentry is a alternative open source error aggregator</%text>
455 <%text>## sentry is a alternative open source error aggregator</%text>
452 <%text>## you must install python packages `sentry` and `raven` to enable</%text>
456 <%text>## you must install python packages `sentry` and `raven` to enable</%text>
453
457
454 sentry.dsn = YOUR_DNS
458 sentry.dsn = YOUR_DNS
455 sentry.servers =
459 sentry.servers =
456 sentry.name =
460 sentry.name =
457 sentry.key =
461 sentry.key =
458 sentry.public_key =
462 sentry.public_key =
459 sentry.secret_key =
463 sentry.secret_key =
460 sentry.project =
464 sentry.project =
461 sentry.site =
465 sentry.site =
462 sentry.include_paths =
466 sentry.include_paths =
463 sentry.exclude_paths =
467 sentry.exclude_paths =
464
468
465 %endif
469 %endif
466 <%text>################################################################################</%text>
470 <%text>################################################################################</%text>
467 <%text>## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##</%text>
471 <%text>## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##</%text>
468 <%text>## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##</%text>
472 <%text>## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##</%text>
469 <%text>## execute malicious code after an exception is raised. ##</%text>
473 <%text>## execute malicious code after an exception is raised. ##</%text>
470 <%text>################################################################################</%text>
474 <%text>################################################################################</%text>
471 set debug = false
475 set debug = false
472
476
473 <%text>##################################</%text>
477 <%text>##################################</%text>
474 <%text>### LOGVIEW CONFIG ###</%text>
478 <%text>### LOGVIEW CONFIG ###</%text>
475 <%text>##################################</%text>
479 <%text>##################################</%text>
476
480
477 logview.sqlalchemy = #faa
481 logview.sqlalchemy = #faa
478 logview.pylons.templating = #bfb
482 logview.pylons.templating = #bfb
479 logview.pylons.util = #eee
483 logview.pylons.util = #eee
480
484
481 <%text>#########################################################</%text>
485 <%text>#########################################################</%text>
482 <%text>### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###</%text>
486 <%text>### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###</%text>
483 <%text>#########################################################</%text>
487 <%text>#########################################################</%text>
484
488
485 %if database_engine == 'sqlite':
489 %if database_engine == 'sqlite':
486 # SQLITE [default]
490 # SQLITE [default]
487 sqlalchemy.url = sqlite:///${here}/kallithea.db?timeout=60
491 sqlalchemy.url = sqlite:///${here}/kallithea.db?timeout=60
488
492
489 %elif database_engine == 'postgres':
493 %elif database_engine == 'postgres':
490 # POSTGRESQL
494 # POSTGRESQL
491 sqlalchemy.url = postgresql://user:pass@localhost/kallithea
495 sqlalchemy.url = postgresql://user:pass@localhost/kallithea
492
496
493 %elif database_engine == 'mysql':
497 %elif database_engine == 'mysql':
494 # MySQL
498 # MySQL
495 sqlalchemy.url = mysql://user:pass@localhost/kallithea?charset=utf8
499 sqlalchemy.url = mysql://user:pass@localhost/kallithea?charset=utf8
496
500
497 %endif
501 %endif
498 # see sqlalchemy docs for others
502 # see sqlalchemy docs for others
499
503
500 sqlalchemy.echo = false
504 sqlalchemy.echo = false
501 sqlalchemy.pool_recycle = 3600
505 sqlalchemy.pool_recycle = 3600
502
506
503 <%text>################################</%text>
507 <%text>################################</%text>
504 <%text>### ALEMBIC CONFIGURATION ####</%text>
508 <%text>### ALEMBIC CONFIGURATION ####</%text>
505 <%text>################################</%text>
509 <%text>################################</%text>
506
510
507 [alembic]
511 [alembic]
508 script_location = kallithea:alembic
512 script_location = kallithea:alembic
509
513
510 <%text>################################</%text>
514 <%text>################################</%text>
511 <%text>### LOGGING CONFIGURATION ####</%text>
515 <%text>### LOGGING CONFIGURATION ####</%text>
512 <%text>################################</%text>
516 <%text>################################</%text>
513
517
514 [loggers]
518 [loggers]
515 keys = root, routes, kallithea, sqlalchemy, beaker, templates, whoosh_indexer
519 keys = root, routes, kallithea, sqlalchemy, gearbox, beaker, templates, whoosh_indexer
516
520
517 [handlers]
521 [handlers]
518 keys = console, console_sql
522 keys = console, console_sql
519
523
520 [formatters]
524 [formatters]
521 keys = generic, color_formatter, color_formatter_sql
525 keys = generic, color_formatter, color_formatter_sql
522
526
523 <%text>#############</%text>
527 <%text>#############</%text>
524 <%text>## LOGGERS ##</%text>
528 <%text>## LOGGERS ##</%text>
525 <%text>#############</%text>
529 <%text>#############</%text>
526
530
527 [logger_root]
531 [logger_root]
528 level = NOTSET
532 level = NOTSET
529 handlers = console
533 handlers = console
530
534
531 [logger_routes]
535 [logger_routes]
532 level = DEBUG
536 level = DEBUG
533 handlers =
537 handlers =
534 qualname = routes.middleware
538 qualname = routes.middleware
535 <%text>## "level = DEBUG" logs the route matched and routing variables.</%text>
539 <%text>## "level = DEBUG" logs the route matched and routing variables.</%text>
536 propagate = 1
540 propagate = 1
537
541
538 [logger_beaker]
542 [logger_beaker]
539 level = DEBUG
543 level = DEBUG
540 handlers =
544 handlers =
541 qualname = beaker.container
545 qualname = beaker.container
542 propagate = 1
546 propagate = 1
543
547
544 [logger_templates]
548 [logger_templates]
545 level = INFO
549 level = INFO
546 handlers =
550 handlers =
547 qualname = pylons.templating
551 qualname = pylons.templating
548 propagate = 1
552 propagate = 1
549
553
550 [logger_kallithea]
554 [logger_kallithea]
551 level = DEBUG
555 level = DEBUG
552 handlers =
556 handlers =
553 qualname = kallithea
557 qualname = kallithea
554 propagate = 1
558 propagate = 1
555
559
560 [logger_gearbox]
561 level = DEBUG
562 handlers =
563 qualname = gearbox
564 propagate = 1
565
556 [logger_sqlalchemy]
566 [logger_sqlalchemy]
557 level = INFO
567 level = INFO
558 handlers = console_sql
568 handlers = console_sql
559 qualname = sqlalchemy.engine
569 qualname = sqlalchemy.engine
560 propagate = 0
570 propagate = 0
561
571
562 [logger_whoosh_indexer]
572 [logger_whoosh_indexer]
563 level = DEBUG
573 level = DEBUG
564 handlers =
574 handlers =
565 qualname = whoosh_indexer
575 qualname = whoosh_indexer
566 propagate = 1
576 propagate = 1
567
577
568 <%text>##############</%text>
578 <%text>##############</%text>
569 <%text>## HANDLERS ##</%text>
579 <%text>## HANDLERS ##</%text>
570 <%text>##############</%text>
580 <%text>##############</%text>
571
581
572 [handler_console]
582 [handler_console]
573 class = StreamHandler
583 class = StreamHandler
574 args = (sys.stderr,)
584 args = (sys.stderr,)
575 level = INFO
585 level = INFO
576 formatter = generic
586 formatter = generic
577
587
578 [handler_console_sql]
588 [handler_console_sql]
579 class = StreamHandler
589 class = StreamHandler
580 args = (sys.stderr,)
590 args = (sys.stderr,)
581 level = WARN
591 level = WARN
582 formatter = generic
592 formatter = generic
583
593
584 <%text>################</%text>
594 <%text>################</%text>
585 <%text>## FORMATTERS ##</%text>
595 <%text>## FORMATTERS ##</%text>
586 <%text>################</%text>
596 <%text>################</%text>
587
597
588 [formatter_generic]
598 [formatter_generic]
589 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
599 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
590 datefmt = %Y-%m-%d %H:%M:%S
600 datefmt = %Y-%m-%d %H:%M:%S
591
601
592 [formatter_color_formatter]
602 [formatter_color_formatter]
593 class = kallithea.lib.colored_formatter.ColorFormatter
603 class = kallithea.lib.colored_formatter.ColorFormatter
594 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
604 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
595 datefmt = %Y-%m-%d %H:%M:%S
605 datefmt = %Y-%m-%d %H:%M:%S
596
606
597 [formatter_color_formatter_sql]
607 [formatter_color_formatter_sql]
598 class = kallithea.lib.colored_formatter.ColorFormatterSql
608 class = kallithea.lib.colored_formatter.ColorFormatterSql
599 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
609 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
600 datefmt = %Y-%m-%d %H:%M:%S
610 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,589 +1,598 b''
1 ################################################################################
1 ################################################################################
2 ################################################################################
2 ################################################################################
3 # Kallithea - Example config #
3 # Kallithea - Example config #
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
8
9 [DEFAULT]
9 [DEFAULT]
10 debug = true
10 debug = true
11 pdebug = false
11 pdebug = false
12
12
13 ################################################################################
13 ################################################################################
14 ## Email settings ##
14 ## Email settings ##
15 ## ##
15 ## ##
16 ## Refer to the documentation ("Email settings") for more details. ##
16 ## Refer to the documentation ("Email settings") for more details. ##
17 ## ##
17 ## ##
18 ## It is recommended to use a valid sender address that passes access ##
18 ## It is recommended to use a valid sender address that passes access ##
19 ## validation and spam filtering in mail servers. ##
19 ## validation and spam filtering in mail servers. ##
20 ################################################################################
20 ################################################################################
21
21
22 ## 'From' header for application emails. You can optionally add a name.
22 ## 'From' header for application emails. You can optionally add a name.
23 ## Default:
23 ## Default:
24 #app_email_from = Kallithea
24 #app_email_from = Kallithea
25 ## Examples:
25 ## Examples:
26 #app_email_from = Kallithea <kallithea-noreply@example.com>
26 #app_email_from = Kallithea <kallithea-noreply@example.com>
27 #app_email_from = kallithea-noreply@example.com
27 #app_email_from = kallithea-noreply@example.com
28
28
29 ## Subject prefix for application emails.
29 ## Subject prefix for application emails.
30 ## A space between this prefix and the real subject is automatically added.
30 ## A space between this prefix and the real subject is automatically added.
31 ## Default:
31 ## Default:
32 #email_prefix =
32 #email_prefix =
33 ## Example:
33 ## Example:
34 #email_prefix = [Kallithea]
34 #email_prefix = [Kallithea]
35
35
36 ## Recipients for error emails and fallback recipients of application mails.
36 ## Recipients for error emails and fallback recipients of application mails.
37 ## Multiple addresses can be specified, space-separated.
37 ## Multiple addresses can be specified, space-separated.
38 ## Only addresses are allowed, do not add any name part.
38 ## Only addresses are allowed, do not add any name part.
39 ## Default:
39 ## Default:
40 #email_to =
40 #email_to =
41 ## Examples:
41 ## Examples:
42 #email_to = admin@example.com
42 #email_to = admin@example.com
43 #email_to = admin@example.com another_admin@example.com
43 #email_to = admin@example.com another_admin@example.com
44
44
45 ## 'From' header for error emails. You can optionally add a name.
45 ## 'From' header for error emails. You can optionally add a name.
46 ## Default:
46 ## Default:
47 #error_email_from = pylons@yourapp.com
47 #error_email_from = pylons@yourapp.com
48 ## Examples:
48 ## Examples:
49 #error_email_from = Kallithea Errors <kallithea-noreply@example.com>
49 #error_email_from = Kallithea Errors <kallithea-noreply@example.com>
50 #error_email_from = paste_error@example.com
50 #error_email_from = paste_error@example.com
51
51
52 ## SMTP server settings
52 ## SMTP server settings
53 ## If specifying credentials, make sure to use secure connections.
53 ## If specifying credentials, make sure to use secure connections.
54 ## Default: Send unencrypted unauthenticated mails to the specified smtp_server.
54 ## Default: Send unencrypted unauthenticated mails to the specified smtp_server.
55 ## For "SSL", use smtp_use_ssl = true and smtp_port = 465.
55 ## For "SSL", use smtp_use_ssl = true and smtp_port = 465.
56 ## For "STARTTLS", use smtp_use_tls = true and smtp_port = 587.
56 ## For "STARTTLS", use smtp_use_tls = true and smtp_port = 587.
57 #smtp_server = smtp.example.com
57 #smtp_server = smtp.example.com
58 #smtp_username =
58 #smtp_username =
59 #smtp_password =
59 #smtp_password =
60 #smtp_port = 25
60 #smtp_port = 25
61 #smtp_use_ssl = false
61 #smtp_use_ssl = false
62 #smtp_use_tls = false
62 #smtp_use_tls = false
63
63
64 [server:main]
64 [server:main]
65 ## PASTE ##
65 ## Gearbox default web server ##
66 #use = egg:Paste#http
66 #use = egg:gearbox#wsgiref
67 ## nr of worker threads to spawn
67 ## nr of worker threads to spawn
68 #threadpool_workers = 1
68 #threadpool_workers = 1
69 ## max request before thread respawn
69 ## max request before thread respawn
70 #threadpool_max_requests = 100
70 #threadpool_max_requests = 100
71 ## option to use threads of process
71 ## option to use threads of process
72 #use_threadpool = true
72 #use_threadpool = true
73
73
74 ## Gearbox gevent web server ##
75 #use = egg:gearbox#gevent
76
74 ## WAITRESS ##
77 ## WAITRESS ##
75 use = egg:waitress#main
78 use = egg:waitress#main
76 ## number of worker threads
79 ## number of worker threads
77 threads = 1
80 threads = 1
78 ## MAX BODY SIZE 100GB
81 ## MAX BODY SIZE 100GB
79 max_request_body_size = 107374182400
82 max_request_body_size = 107374182400
80 ## use poll instead of select, fixes fd limits, may not work on old
83 ## use poll instead of select, fixes fd limits, may not work on old
81 ## windows systems.
84 ## windows systems.
82 #asyncore_use_poll = True
85 #asyncore_use_poll = True
83
86
84 ## GUNICORN ##
87 ## GUNICORN ##
85 #use = egg:gunicorn#main
88 #use = egg:gunicorn#main
86 ## number of process workers. You must set `instance_id = *` when this option
89 ## number of process workers. You must set `instance_id = *` when this option
87 ## is set to more than one worker
90 ## is set to more than one worker
88 #workers = 1
91 #workers = 1
89 ## process name
92 ## process name
90 #proc_name = kallithea
93 #proc_name = kallithea
91 ## type of worker class, one of sync, eventlet, gevent, tornado
94 ## type of worker class, one of sync, eventlet, gevent, tornado
92 ## recommended for bigger setup is using of of other than sync one
95 ## recommended for bigger setup is using of of other than sync one
93 #worker_class = sync
96 #worker_class = sync
94 #max_requests = 1000
97 #max_requests = 1000
95 ## amount of time a worker can handle request before it gets killed and
98 ## amount of time a worker can handle request before it gets killed and
96 ## restarted
99 ## restarted
97 #timeout = 3600
100 #timeout = 3600
98
101
99 ## UWSGI ##
102 ## UWSGI ##
100 ## run with uwsgi --ini-paste-logged <inifile.ini>
103 ## run with uwsgi --ini-paste-logged <inifile.ini>
101 #[uwsgi]
104 #[uwsgi]
102 #socket = /tmp/uwsgi.sock
105 #socket = /tmp/uwsgi.sock
103 #master = true
106 #master = true
104 #http = 127.0.0.1:5000
107 #http = 127.0.0.1:5000
105
108
106 ## set as deamon and redirect all output to file
109 ## set as deamon and redirect all output to file
107 #daemonize = ./uwsgi_kallithea.log
110 #daemonize = ./uwsgi_kallithea.log
108
111
109 ## master process PID
112 ## master process PID
110 #pidfile = ./uwsgi_kallithea.pid
113 #pidfile = ./uwsgi_kallithea.pid
111
114
112 ## stats server with workers statistics, use uwsgitop
115 ## stats server with workers statistics, use uwsgitop
113 ## for monitoring, `uwsgitop 127.0.0.1:1717`
116 ## for monitoring, `uwsgitop 127.0.0.1:1717`
114 #stats = 127.0.0.1:1717
117 #stats = 127.0.0.1:1717
115 #memory-report = true
118 #memory-report = true
116
119
117 ## log 5XX errors
120 ## log 5XX errors
118 #log-5xx = true
121 #log-5xx = true
119
122
120 ## Set the socket listen queue size.
123 ## Set the socket listen queue size.
121 #listen = 256
124 #listen = 256
122
125
123 ## Gracefully Reload workers after the specified amount of managed requests
126 ## Gracefully Reload workers after the specified amount of managed requests
124 ## (avoid memory leaks).
127 ## (avoid memory leaks).
125 #max-requests = 1000
128 #max-requests = 1000
126
129
127 ## enable large buffers
130 ## enable large buffers
128 #buffer-size = 65535
131 #buffer-size = 65535
129
132
130 ## socket and http timeouts ##
133 ## socket and http timeouts ##
131 #http-timeout = 3600
134 #http-timeout = 3600
132 #socket-timeout = 3600
135 #socket-timeout = 3600
133
136
134 ## Log requests slower than the specified number of milliseconds.
137 ## Log requests slower than the specified number of milliseconds.
135 #log-slow = 10
138 #log-slow = 10
136
139
137 ## Exit if no app can be loaded.
140 ## Exit if no app can be loaded.
138 #need-app = true
141 #need-app = true
139
142
140 ## Set lazy mode (load apps in workers instead of master).
143 ## Set lazy mode (load apps in workers instead of master).
141 #lazy = true
144 #lazy = true
142
145
143 ## scaling ##
146 ## scaling ##
144 ## set cheaper algorithm to use, if not set default will be used
147 ## set cheaper algorithm to use, if not set default will be used
145 #cheaper-algo = spare
148 #cheaper-algo = spare
146
149
147 ## minimum number of workers to keep at all times
150 ## minimum number of workers to keep at all times
148 #cheaper = 1
151 #cheaper = 1
149
152
150 ## number of workers to spawn at startup
153 ## number of workers to spawn at startup
151 #cheaper-initial = 1
154 #cheaper-initial = 1
152
155
153 ## maximum number of workers that can be spawned
156 ## maximum number of workers that can be spawned
154 #workers = 4
157 #workers = 4
155
158
156 ## how many workers should be spawned at a time
159 ## how many workers should be spawned at a time
157 #cheaper-step = 1
160 #cheaper-step = 1
158
161
159 ## COMMON ##
162 ## COMMON ##
160 host = 127.0.0.1
163 host = 127.0.0.1
161 port = 5000
164 port = 5000
162
165
163 ## middleware for hosting the WSGI application under a URL prefix
166 ## middleware for hosting the WSGI application under a URL prefix
164 #[filter:proxy-prefix]
167 #[filter:proxy-prefix]
165 #use = egg:PasteDeploy#prefix
168 #use = egg:PasteDeploy#prefix
166 #prefix = /<your-prefix>
169 #prefix = /<your-prefix>
167
170
168 [app:main]
171 [app:main]
169 use = egg:kallithea
172 use = egg:kallithea
170 ## enable proxy prefix middleware
173 ## enable proxy prefix middleware
171 #filter-with = proxy-prefix
174 #filter-with = proxy-prefix
172
175
173 full_stack = true
176 full_stack = true
174 static_files = true
177 static_files = true
175 ## Available Languages:
178 ## Available Languages:
176 ## cs de fr hu ja nl_BE pl pt_BR ru sk zh_CN zh_TW
179 ## cs de fr hu ja nl_BE pl pt_BR ru sk zh_CN zh_TW
177 lang =
180 lang =
178 cache_dir = %(here)s/data
181 cache_dir = %(here)s/data
179 index_dir = %(here)s/data/index
182 index_dir = %(here)s/data/index
180
183
181 ## perform a full repository scan on each server start, this should be
184 ## perform a full repository scan on each server start, this should be
182 ## set to false after first startup, to allow faster server restarts.
185 ## set to false after first startup, to allow faster server restarts.
183 initial_repo_scan = false
186 initial_repo_scan = false
184
187
185 ## uncomment and set this path to use archive download cache
188 ## uncomment and set this path to use archive download cache
186 archive_cache_dir = %(here)s/tarballcache
189 archive_cache_dir = %(here)s/tarballcache
187
190
188 ## change this to unique ID for security
191 ## change this to unique ID for security
189 app_instance_uuid = ${app_instance_uuid}
192 app_instance_uuid = ${app_instance_uuid}
190
193
191 ## cut off limit for large diffs (size in bytes)
194 ## cut off limit for large diffs (size in bytes)
192 cut_off_limit = 256000
195 cut_off_limit = 256000
193
196
194 ## force https in Kallithea, fixes https redirects, assumes it's always https
197 ## force https in Kallithea, fixes https redirects, assumes it's always https
195 force_https = false
198 force_https = false
196
199
197 ## use Strict-Transport-Security headers
200 ## use Strict-Transport-Security headers
198 use_htsts = false
201 use_htsts = false
199
202
200 ## number of commits stats will parse on each iteration
203 ## number of commits stats will parse on each iteration
201 commit_parse_limit = 25
204 commit_parse_limit = 25
202
205
203 ## path to git executable
206 ## path to git executable
204 git_path = git
207 git_path = git
205
208
206 ## git rev filter option, --all is the default filter, if you need to
209 ## git rev filter option, --all is the default filter, if you need to
207 ## hide all refs in changelog switch this to --branches --tags
210 ## hide all refs in changelog switch this to --branches --tags
208 #git_rev_filter = --branches --tags
211 #git_rev_filter = --branches --tags
209
212
210 ## RSS feed options
213 ## RSS feed options
211 rss_cut_off_limit = 256000
214 rss_cut_off_limit = 256000
212 rss_items_per_page = 10
215 rss_items_per_page = 10
213 rss_include_diff = false
216 rss_include_diff = false
214
217
215 ## options for showing and identifying changesets
218 ## options for showing and identifying changesets
216 show_sha_length = 12
219 show_sha_length = 12
217 show_revision_number = false
220 show_revision_number = false
218
221
219 ## Canonical URL to use when creating full URLs in UI and texts.
222 ## Canonical URL to use when creating full URLs in UI and texts.
220 ## Useful when the site is available under different names or protocols.
223 ## Useful when the site is available under different names or protocols.
221 ## Defaults to what is provided in the WSGI environment.
224 ## Defaults to what is provided in the WSGI environment.
222 #canonical_url = https://kallithea.example.com/repos
225 #canonical_url = https://kallithea.example.com/repos
223
226
224 ## gist URL alias, used to create nicer urls for gist. This should be an
227 ## gist URL alias, used to create nicer urls for gist. This should be an
225 ## url that does rewrites to _admin/gists/<gistid>.
228 ## url that does rewrites to _admin/gists/<gistid>.
226 ## example: http://gist.example.com/{gistid}. Empty means use the internal
229 ## example: http://gist.example.com/{gistid}. Empty means use the internal
227 ## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid>
230 ## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid>
228 gist_alias_url =
231 gist_alias_url =
229
232
230 ## white list of API enabled controllers. This allows to add list of
233 ## white list of API enabled controllers. This allows to add list of
231 ## controllers to which access will be enabled by api_key. eg: to enable
234 ## controllers to which access will be enabled by api_key. eg: to enable
232 ## api access to raw_files put `FilesController:raw`, to enable access to patches
235 ## api access to raw_files put `FilesController:raw`, to enable access to patches
233 ## add `ChangesetController:changeset_patch`. This list should be "," separated
236 ## add `ChangesetController:changeset_patch`. This list should be "," separated
234 ## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
237 ## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
235 ## Recommended settings below are commented out:
238 ## Recommended settings below are commented out:
236 api_access_controllers_whitelist =
239 api_access_controllers_whitelist =
237 # ChangesetController:changeset_patch,
240 # ChangesetController:changeset_patch,
238 # ChangesetController:changeset_raw,
241 # ChangesetController:changeset_raw,
239 # FilesController:raw,
242 # FilesController:raw,
240 # FilesController:archivefile
243 # FilesController:archivefile
241
244
242 ## default encoding used to convert from and to unicode
245 ## default encoding used to convert from and to unicode
243 ## can be also a comma separated list of encoding in case of mixed encodings
246 ## can be also a comma separated list of encoding in case of mixed encodings
244 default_encoding = utf8
247 default_encoding = utf8
245
248
246 ## issue tracker for Kallithea (leave blank to disable, absent for default)
249 ## issue tracker for Kallithea (leave blank to disable, absent for default)
247 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
250 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
248
251
249 ## issue tracking mapping for commits messages
252 ## issue tracking mapping for commits messages
250 ## comment out issue_pat, issue_server, issue_prefix to enable
253 ## comment out issue_pat, issue_server, issue_prefix to enable
251
254
252 ## pattern to get the issues from commit messages
255 ## pattern to get the issues from commit messages
253 ## default one used here is #<numbers> with a regex passive group for `#`
256 ## default one used here is #<numbers> with a regex passive group for `#`
254 ## {id} will be all groups matched from this pattern
257 ## {id} will be all groups matched from this pattern
255
258
256 issue_pat = (?:\s*#)(\d+)
259 issue_pat = (?:\s*#)(\d+)
257
260
258 ## server url to the issue, each {id} will be replaced with match
261 ## server url to the issue, each {id} will be replaced with match
259 ## fetched from the regex and {repo} is replaced with full repository name
262 ## fetched from the regex and {repo} is replaced with full repository name
260 ## including groups {repo_name} is replaced with just name of repo
263 ## including groups {repo_name} is replaced with just name of repo
261
264
262 issue_server_link = https://issues.example.com/{repo}/issue/{id}
265 issue_server_link = https://issues.example.com/{repo}/issue/{id}
263
266
264 ## prefix to add to link to indicate it's an url
267 ## prefix to add to link to indicate it's an url
265 ## #314 will be replaced by <issue_prefix><id>
268 ## #314 will be replaced by <issue_prefix><id>
266
269
267 issue_prefix = #
270 issue_prefix = #
268
271
269 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
272 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
270 ## multiple patterns, to other issues server, wiki or others
273 ## multiple patterns, to other issues server, wiki or others
271 ## below an example how to create a wiki pattern
274 ## below an example how to create a wiki pattern
272 # wiki-some-id -> https://wiki.example.com/some-id
275 # wiki-some-id -> https://wiki.example.com/some-id
273
276
274 #issue_pat_wiki = (?:wiki-)(.+)
277 #issue_pat_wiki = (?:wiki-)(.+)
275 #issue_server_link_wiki = https://wiki.example.com/{id}
278 #issue_server_link_wiki = https://wiki.example.com/{id}
276 #issue_prefix_wiki = WIKI-
279 #issue_prefix_wiki = WIKI-
277
280
278 ## alternative return HTTP header for failed authentication. Default HTTP
281 ## alternative return HTTP header for failed authentication. Default HTTP
279 ## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
282 ## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
280 ## handling that. Set this variable to 403 to return HTTPForbidden
283 ## handling that. Set this variable to 403 to return HTTPForbidden
281 auth_ret_code =
284 auth_ret_code =
282
285
283 ## locking return code. When repository is locked return this HTTP code. 2XX
286 ## locking return code. When repository is locked return this HTTP code. 2XX
284 ## codes don't break the transactions while 4XX codes do
287 ## codes don't break the transactions while 4XX codes do
285 lock_ret_code = 423
288 lock_ret_code = 423
286
289
287 ## allows to change the repository location in settings page
290 ## allows to change the repository location in settings page
288 allow_repo_location_change = True
291 allow_repo_location_change = True
289
292
290 ## allows to setup custom hooks in settings page
293 ## allows to setup custom hooks in settings page
291 allow_custom_hooks_settings = True
294 allow_custom_hooks_settings = True
292
295
293 ## extra extensions for indexing, space separated and without the leading '.'.
296 ## extra extensions for indexing, space separated and without the leading '.'.
294 # index.extensions =
297 # index.extensions =
295 # gemfile
298 # gemfile
296 # lock
299 # lock
297
300
298 ## extra filenames for indexing, space separated
301 ## extra filenames for indexing, space separated
299 # index.filenames =
302 # index.filenames =
300 # .dockerignore
303 # .dockerignore
301 # .editorconfig
304 # .editorconfig
302 # INSTALL
305 # INSTALL
303 # CHANGELOG
306 # CHANGELOG
304
307
305 ####################################
308 ####################################
306 ### CELERY CONFIG ####
309 ### CELERY CONFIG ####
307 ####################################
310 ####################################
308
311
309 use_celery = false
312 use_celery = false
310
313
311 ## Example: connect to the virtual host 'rabbitmqhost' on localhost as rabbitmq:
314 ## Example: connect to the virtual host 'rabbitmqhost' on localhost as rabbitmq:
312 broker.url = amqp://rabbitmq:qewqew@localhost:5672/rabbitmqhost
315 broker.url = amqp://rabbitmq:qewqew@localhost:5672/rabbitmqhost
313
316
314 celery.imports = kallithea.lib.celerylib.tasks
317 celery.imports = kallithea.lib.celerylib.tasks
315 celery.accept.content = pickle
318 celery.accept.content = pickle
316 celery.result.backend = amqp
319 celery.result.backend = amqp
317 celery.result.dburi = amqp://
320 celery.result.dburi = amqp://
318 celery.result.serialier = json
321 celery.result.serialier = json
319
322
320 #celery.send.task.error.emails = true
323 #celery.send.task.error.emails = true
321 #celery.amqp.task.result.expires = 18000
324 #celery.amqp.task.result.expires = 18000
322
325
323 celeryd.concurrency = 2
326 celeryd.concurrency = 2
324 celeryd.max.tasks.per.child = 1
327 celeryd.max.tasks.per.child = 1
325
328
326 ## If true, tasks will never be sent to the queue, but executed locally instead.
329 ## If true, tasks will never be sent to the queue, but executed locally instead.
327 celery.always.eager = false
330 celery.always.eager = false
328
331
329 ####################################
332 ####################################
330 ### BEAKER CACHE ####
333 ### BEAKER CACHE ####
331 ####################################
334 ####################################
332
335
333 beaker.cache.data_dir = %(here)s/data/cache/data
336 beaker.cache.data_dir = %(here)s/data/cache/data
334 beaker.cache.lock_dir = %(here)s/data/cache/lock
337 beaker.cache.lock_dir = %(here)s/data/cache/lock
335
338
336 beaker.cache.regions = short_term,long_term,sql_cache_short
339 beaker.cache.regions = short_term,long_term,sql_cache_short
337
340
338 beaker.cache.short_term.type = memory
341 beaker.cache.short_term.type = memory
339 beaker.cache.short_term.expire = 60
342 beaker.cache.short_term.expire = 60
340 beaker.cache.short_term.key_length = 256
343 beaker.cache.short_term.key_length = 256
341
344
342 beaker.cache.long_term.type = memory
345 beaker.cache.long_term.type = memory
343 beaker.cache.long_term.expire = 36000
346 beaker.cache.long_term.expire = 36000
344 beaker.cache.long_term.key_length = 256
347 beaker.cache.long_term.key_length = 256
345
348
346 beaker.cache.sql_cache_short.type = memory
349 beaker.cache.sql_cache_short.type = memory
347 beaker.cache.sql_cache_short.expire = 10
350 beaker.cache.sql_cache_short.expire = 10
348 beaker.cache.sql_cache_short.key_length = 256
351 beaker.cache.sql_cache_short.key_length = 256
349
352
350 ####################################
353 ####################################
351 ### BEAKER SESSION ####
354 ### BEAKER SESSION ####
352 ####################################
355 ####################################
353
356
354 ## Name of session cookie. Should be unique for a given host and path, even when running
357 ## Name of session cookie. Should be unique for a given host and path, even when running
355 ## on different ports. Otherwise, cookie sessions will be shared and messed up.
358 ## on different ports. Otherwise, cookie sessions will be shared and messed up.
356 beaker.session.key = kallithea
359 beaker.session.key = kallithea
357 ## Sessions should always only be accessible by the browser, not directly by JavaScript.
360 ## Sessions should always only be accessible by the browser, not directly by JavaScript.
358 beaker.session.httponly = true
361 beaker.session.httponly = true
359 ## Session lifetime. 2592000 seconds is 30 days.
362 ## Session lifetime. 2592000 seconds is 30 days.
360 beaker.session.timeout = 2592000
363 beaker.session.timeout = 2592000
361
364
362 ## Server secret used with HMAC to ensure integrity of cookies.
365 ## Server secret used with HMAC to ensure integrity of cookies.
363 beaker.session.secret = ${app_instance_uuid}
366 beaker.session.secret = ${app_instance_uuid}
364 ## Further, encrypt the data with AES.
367 ## Further, encrypt the data with AES.
365 #beaker.session.encrypt_key = <key_for_encryption>
368 #beaker.session.encrypt_key = <key_for_encryption>
366 #beaker.session.validate_key = <validation_key>
369 #beaker.session.validate_key = <validation_key>
367
370
368 ## Type of storage used for the session, current types are
371 ## Type of storage used for the session, current types are
369 ## dbm, file, memcached, database, and memory.
372 ## dbm, file, memcached, database, and memory.
370
373
371 ## File system storage of session data. (default)
374 ## File system storage of session data. (default)
372 #beaker.session.type = file
375 #beaker.session.type = file
373
376
374 ## Cookie only, store all session data inside the cookie. Requires secure secrets.
377 ## Cookie only, store all session data inside the cookie. Requires secure secrets.
375 #beaker.session.type = cookie
378 #beaker.session.type = cookie
376
379
377 ## Database storage of session data.
380 ## Database storage of session data.
378 #beaker.session.type = ext:database
381 #beaker.session.type = ext:database
379 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/kallithea
382 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/kallithea
380 #beaker.session.table_name = db_session
383 #beaker.session.table_name = db_session
381
384
382 ############################
385 ############################
383 ## ERROR HANDLING SYSTEMS ##
386 ## ERROR HANDLING SYSTEMS ##
384 ############################
387 ############################
385
388
386 ####################
389 ####################
387 ### [appenlight] ###
390 ### [appenlight] ###
388 ####################
391 ####################
389
392
390 ## AppEnlight is tailored to work with Kallithea, see
393 ## AppEnlight is tailored to work with Kallithea, see
391 ## http://appenlight.com for details how to obtain an account
394 ## http://appenlight.com for details how to obtain an account
392 ## you must install python package `appenlight_client` to make it work
395 ## you must install python package `appenlight_client` to make it work
393
396
394 ## appenlight enabled
397 ## appenlight enabled
395 appenlight = false
398 appenlight = false
396
399
397 appenlight.server_url = https://api.appenlight.com
400 appenlight.server_url = https://api.appenlight.com
398 appenlight.api_key = YOUR_API_KEY
401 appenlight.api_key = YOUR_API_KEY
399
402
400 ## TWEAK AMOUNT OF INFO SENT HERE
403 ## TWEAK AMOUNT OF INFO SENT HERE
401
404
402 ## enables 404 error logging (default False)
405 ## enables 404 error logging (default False)
403 appenlight.report_404 = false
406 appenlight.report_404 = false
404
407
405 ## time in seconds after request is considered being slow (default 1)
408 ## time in seconds after request is considered being slow (default 1)
406 appenlight.slow_request_time = 1
409 appenlight.slow_request_time = 1
407
410
408 ## record slow requests in application
411 ## record slow requests in application
409 ## (needs to be enabled for slow datastore recording and time tracking)
412 ## (needs to be enabled for slow datastore recording and time tracking)
410 appenlight.slow_requests = true
413 appenlight.slow_requests = true
411
414
412 ## enable hooking to application loggers
415 ## enable hooking to application loggers
413 #appenlight.logging = true
416 #appenlight.logging = true
414
417
415 ## minimum log level for log capture
418 ## minimum log level for log capture
416 #appenlight.logging.level = WARNING
419 #appenlight.logging.level = WARNING
417
420
418 ## send logs only from erroneous/slow requests
421 ## send logs only from erroneous/slow requests
419 ## (saves API quota for intensive logging)
422 ## (saves API quota for intensive logging)
420 appenlight.logging_on_error = false
423 appenlight.logging_on_error = false
421
424
422 ## list of additional keywords that should be grabbed from environ object
425 ## list of additional keywords that should be grabbed from environ object
423 ## can be string with comma separated list of words in lowercase
426 ## can be string with comma separated list of words in lowercase
424 ## (by default client will always send following info:
427 ## (by default client will always send following info:
425 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
428 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
426 ## start with HTTP* this list be extended with additional keywords here
429 ## start with HTTP* this list be extended with additional keywords here
427 appenlight.environ_keys_whitelist =
430 appenlight.environ_keys_whitelist =
428
431
429 ## list of keywords that should be blanked from request object
432 ## list of keywords that should be blanked from request object
430 ## can be string with comma separated list of words in lowercase
433 ## can be string with comma separated list of words in lowercase
431 ## (by default client will always blank keys that contain following words
434 ## (by default client will always blank keys that contain following words
432 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
435 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
433 ## this list be extended with additional keywords set here
436 ## this list be extended with additional keywords set here
434 appenlight.request_keys_blacklist =
437 appenlight.request_keys_blacklist =
435
438
436 ## list of namespaces that should be ignores when gathering log entries
439 ## list of namespaces that should be ignores when gathering log entries
437 ## can be string with comma separated list of namespaces
440 ## can be string with comma separated list of namespaces
438 ## (by default the client ignores own entries: appenlight_client.client)
441 ## (by default the client ignores own entries: appenlight_client.client)
439 appenlight.log_namespace_blacklist =
442 appenlight.log_namespace_blacklist =
440
443
441 ################
444 ################
442 ### [sentry] ###
445 ### [sentry] ###
443 ################
446 ################
444
447
445 ## sentry is a alternative open source error aggregator
448 ## sentry is a alternative open source error aggregator
446 ## you must install python packages `sentry` and `raven` to enable
449 ## you must install python packages `sentry` and `raven` to enable
447
450
448 sentry.dsn = YOUR_DNS
451 sentry.dsn = YOUR_DNS
449 sentry.servers =
452 sentry.servers =
450 sentry.name =
453 sentry.name =
451 sentry.key =
454 sentry.key =
452 sentry.public_key =
455 sentry.public_key =
453 sentry.secret_key =
456 sentry.secret_key =
454 sentry.project =
457 sentry.project =
455 sentry.site =
458 sentry.site =
456 sentry.include_paths =
459 sentry.include_paths =
457 sentry.exclude_paths =
460 sentry.exclude_paths =
458
461
459 ################################################################################
462 ################################################################################
460 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
463 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
461 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
464 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
462 ## execute malicious code after an exception is raised. ##
465 ## execute malicious code after an exception is raised. ##
463 ################################################################################
466 ################################################################################
464 set debug = false
467 set debug = false
465
468
466 ##################################
469 ##################################
467 ### LOGVIEW CONFIG ###
470 ### LOGVIEW CONFIG ###
468 ##################################
471 ##################################
469
472
470 logview.sqlalchemy = #faa
473 logview.sqlalchemy = #faa
471 logview.pylons.templating = #bfb
474 logview.pylons.templating = #bfb
472 logview.pylons.util = #eee
475 logview.pylons.util = #eee
473
476
474 #########################################################
477 #########################################################
475 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
478 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
476 #########################################################
479 #########################################################
477
480
478 # SQLITE [default]
481 # SQLITE [default]
479 sqlalchemy.url = sqlite:///%(here)s/kallithea.db?timeout=60
482 sqlalchemy.url = sqlite:///%(here)s/kallithea.db?timeout=60
480
483
481 # POSTGRESQL
484 # POSTGRESQL
482 #sqlalchemy.url = postgresql://user:pass@localhost/kallithea
485 #sqlalchemy.url = postgresql://user:pass@localhost/kallithea
483
486
484 # MySQL
487 # MySQL
485 #sqlalchemy.url = mysql://user:pass@localhost/kallithea?charset=utf8
488 #sqlalchemy.url = mysql://user:pass@localhost/kallithea?charset=utf8
486
489
487 # see sqlalchemy docs for others
490 # see sqlalchemy docs for others
488
491
489 sqlalchemy.echo = false
492 sqlalchemy.echo = false
490 sqlalchemy.pool_recycle = 3600
493 sqlalchemy.pool_recycle = 3600
491
494
492 ################################
495 ################################
493 ### ALEMBIC CONFIGURATION ####
496 ### ALEMBIC CONFIGURATION ####
494 ################################
497 ################################
495
498
496 [alembic]
499 [alembic]
497 script_location = kallithea:alembic
500 script_location = kallithea:alembic
498
501
499 ################################
502 ################################
500 ### LOGGING CONFIGURATION ####
503 ### LOGGING CONFIGURATION ####
501 ################################
504 ################################
502
505
503 [loggers]
506 [loggers]
504 keys = root, routes, kallithea, sqlalchemy, beaker, templates, whoosh_indexer
507 keys = root, routes, kallithea, sqlalchemy, gearbox, beaker, templates, whoosh_indexer
505
508
506 [handlers]
509 [handlers]
507 keys = console, console_sql
510 keys = console, console_sql
508
511
509 [formatters]
512 [formatters]
510 keys = generic, color_formatter, color_formatter_sql
513 keys = generic, color_formatter, color_formatter_sql
511
514
512 #############
515 #############
513 ## LOGGERS ##
516 ## LOGGERS ##
514 #############
517 #############
515
518
516 [logger_root]
519 [logger_root]
517 level = NOTSET
520 level = NOTSET
518 handlers = console
521 handlers = console
519
522
520 [logger_routes]
523 [logger_routes]
521 level = DEBUG
524 level = DEBUG
522 handlers =
525 handlers =
523 qualname = routes.middleware
526 qualname = routes.middleware
524 ## "level = DEBUG" logs the route matched and routing variables.
527 ## "level = DEBUG" logs the route matched and routing variables.
525 propagate = 1
528 propagate = 1
526
529
527 [logger_beaker]
530 [logger_beaker]
528 level = DEBUG
531 level = DEBUG
529 handlers =
532 handlers =
530 qualname = beaker.container
533 qualname = beaker.container
531 propagate = 1
534 propagate = 1
532
535
533 [logger_templates]
536 [logger_templates]
534 level = INFO
537 level = INFO
535 handlers =
538 handlers =
536 qualname = pylons.templating
539 qualname = pylons.templating
537 propagate = 1
540 propagate = 1
538
541
539 [logger_kallithea]
542 [logger_kallithea]
540 level = DEBUG
543 level = DEBUG
541 handlers =
544 handlers =
542 qualname = kallithea
545 qualname = kallithea
543 propagate = 1
546 propagate = 1
544
547
548 [logger_gearbox]
549 level = DEBUG
550 handlers =
551 qualname = gearbox
552 propagate = 1
553
545 [logger_sqlalchemy]
554 [logger_sqlalchemy]
546 level = INFO
555 level = INFO
547 handlers = console_sql
556 handlers = console_sql
548 qualname = sqlalchemy.engine
557 qualname = sqlalchemy.engine
549 propagate = 0
558 propagate = 0
550
559
551 [logger_whoosh_indexer]
560 [logger_whoosh_indexer]
552 level = DEBUG
561 level = DEBUG
553 handlers =
562 handlers =
554 qualname = whoosh_indexer
563 qualname = whoosh_indexer
555 propagate = 1
564 propagate = 1
556
565
557 ##############
566 ##############
558 ## HANDLERS ##
567 ## HANDLERS ##
559 ##############
568 ##############
560
569
561 [handler_console]
570 [handler_console]
562 class = StreamHandler
571 class = StreamHandler
563 args = (sys.stderr,)
572 args = (sys.stderr,)
564 level = INFO
573 level = INFO
565 formatter = generic
574 formatter = generic
566
575
567 [handler_console_sql]
576 [handler_console_sql]
568 class = StreamHandler
577 class = StreamHandler
569 args = (sys.stderr,)
578 args = (sys.stderr,)
570 level = WARN
579 level = WARN
571 formatter = generic
580 formatter = generic
572
581
573 ################
582 ################
574 ## FORMATTERS ##
583 ## FORMATTERS ##
575 ################
584 ################
576
585
577 [formatter_generic]
586 [formatter_generic]
578 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
587 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
579 datefmt = %Y-%m-%d %H:%M:%S
588 datefmt = %Y-%m-%d %H:%M:%S
580
589
581 [formatter_color_formatter]
590 [formatter_color_formatter]
582 class = kallithea.lib.colored_formatter.ColorFormatter
591 class = kallithea.lib.colored_formatter.ColorFormatter
583 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
592 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
584 datefmt = %Y-%m-%d %H:%M:%S
593 datefmt = %Y-%m-%d %H:%M:%S
585
594
586 [formatter_color_formatter_sql]
595 [formatter_color_formatter_sql]
587 class = kallithea.lib.colored_formatter.ColorFormatterSql
596 class = kallithea.lib.colored_formatter.ColorFormatterSql
588 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
597 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
589 datefmt = %Y-%m-%d %H:%M:%S
598 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,11 +1,12 b''
1 from paste.script.command import Command
1 from gearbox.command import Command
2
2
3 class UpgradeDb(Command):
3 class UpgradeDb(Command):
4 hidden = True
4 '''(removed)'''
5 summary = '(removed)'
5
6 deprecated = True
6
7
7 def run(self, args):
8 def run(self, args):
8 raise SystemExit(
9 raise SystemExit(
9 'The "paster upgrade-db" command has been removed; please see the docs:\n'
10 'The "paster upgrade-db" command has been removed; please see the docs:\n'
10 ' https://kallithea.readthedocs.io/en/default/upgrade.html'
11 ' https://kallithea.readthedocs.io/en/default/upgrade.html'
11 )
12 )
@@ -1,79 +1,72 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
14 """
15 kallithea.lib.paster_commands.cache_keys
15 kallithea.lib.paster_commands.cache_keys
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17
17
18 cleanup-keys paster command for Kallithea
18 cleanup-keys gearbox command for Kallithea
19
19
20
20
21 This file was forked by the Kallithea project in July 2014.
21 This file was forked by the Kallithea project in July 2014.
22 Original author and date, and relevant copyright and licensing information is below:
22 Original author and date, and relevant copyright and licensing information is below:
23 :created_on: mar 27, 2013
23 :created_on: mar 27, 2013
24 :author: marcink
24 :author: marcink
25 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 :copyright: (c) 2013 RhodeCode GmbH, and others.
26 :license: GPLv3, see LICENSE.md for more details.
26 :license: GPLv3, see LICENSE.md for more details.
27 """
27 """
28
28
29
29
30 import os
30 import os
31 import sys
31 import sys
32
32
33 from kallithea.lib.paster_commands.common import BasePasterCommand
33 from kallithea.lib.paster_commands.common import BasePasterCommand
34 from kallithea.model.meta import Session
34 from kallithea.model.meta import Session
35 from kallithea.lib.utils2 import safe_str
35 from kallithea.lib.utils2 import safe_str
36 from kallithea.model.db import CacheInvalidation
36 from kallithea.model.db import CacheInvalidation
37
37
38
38
39 class Command(BasePasterCommand):
39 class Command(BasePasterCommand):
40
40 "Kallithea: Utilities for managing caching of database content"
41 max_args = 1
42 min_args = 1
43
41
44 usage = "CONFIG_FILE"
42 def take_action(self, args):
45 group_name = "Kallithea"
46 takes_config_file = -1
47 parser = BasePasterCommand.standard_parser(verbose=True)
48 summary = "Cache keys utils"
49
50 def command(self):
51 #get SqlAlchemy session
52 self._init_session()
53
54 _caches = CacheInvalidation.query().order_by(CacheInvalidation.cache_key).all()
43 _caches = CacheInvalidation.query().order_by(CacheInvalidation.cache_key).all()
55 if self.options.show:
44 if args.show:
56 for c_obj in _caches:
45 for c_obj in _caches:
57 print 'key:%s active:%s' % (safe_str(c_obj.cache_key), c_obj.cache_active)
46 print 'key:%s active:%s' % (safe_str(c_obj.cache_key), c_obj.cache_active)
58 elif self.options.cleanup:
47 elif args.cleanup:
59 for c_obj in _caches:
48 for c_obj in _caches:
60 Session().delete(c_obj)
49 Session().delete(c_obj)
61 print 'Removing key: %s' % (safe_str(c_obj.cache_key))
50 print 'Removing key: %s' % (safe_str(c_obj.cache_key))
62 Session().commit()
51 Session().commit()
63 else:
52 else:
64 print 'Nothing done, exiting...'
53 print 'Nothing done, exiting...'
65
54
66 def update_parser(self):
55 def get_parser(self, prog_name):
67 self.parser.add_option(
56 parser = super(Command, self).get_parser(prog_name)
57
58 parser.add_argument(
68 '--show',
59 '--show',
69 action='store_true',
60 action='store_true',
70 dest='show',
61 dest='show',
71 help=("show existing cache keys with together with status")
62 help="show existing cache keys with together with status",
72 )
63 )
73
64
74 self.parser.add_option(
65 parser.add_argument(
75 '--cleanup',
66 '--cleanup',
76 action="store_true",
67 action="store_true",
77 dest="cleanup",
68 dest="cleanup",
78 help="cleanup existing cache keys"
69 help="cleanup existing cache keys",
79 )
70 )
71
72 return parser
@@ -1,46 +1,50 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 import argparse
4
3 import kallithea
5 import kallithea
4 from kallithea.lib.paster_commands.common import BasePasterCommand
6 from kallithea.lib.paster_commands.common import BasePasterCommand
5 from kallithea.lib.utils import load_rcextensions
7 from kallithea.lib.utils import load_rcextensions
6 from kallithea.lib.utils2 import str2bool
8 from kallithea.lib.utils2 import str2bool
7
9
8 __all__ = ['Command']
10 __all__ = ['Command']
9
11
10
12
11 class Command(BasePasterCommand):
13 class Command(BasePasterCommand):
12 """Start the celery worker
14 """Kallithea: Celery worker for asynchronous tasks"""
13
14 Starts the celery worker that uses a paste.deploy configuration
15 file.
16 """
17
15
18 usage = 'CONFIG_FILE [celeryd options...]'
16 # Starts the celery worker using configuration from a paste.deploy
19 summary = __doc__.splitlines()[0]
17 # configuration file.
20 description = "".join(__doc__.splitlines()[2:])
21 group_name = "Kallithea"
22
23 parser = BasePasterCommand.standard_parser(quiet=True)
24
18
25 def update_parser(self):
19 requires_db_session = False # will start session on demand
26 from kallithea.lib import celerypylons
27 cmd = celerypylons.worker.worker(celerypylons.app.app_or_default())
28 for x in cmd.get_options():
29 self.parser.add_option(x)
30
20
31 def command(self):
21 def take_action(self, args):
32 from kallithea.lib import celerypylons
22 from kallithea.lib import celerypylons
33 from tg import config
23 from tg import config
34 try:
24 try:
35 CELERY_ON = str2bool(config['app_conf'].get('use_celery'))
25 CELERY_ON = str2bool(config['app_conf'].get('use_celery'))
36 except KeyError:
26 except KeyError:
37 CELERY_ON = False
27 CELERY_ON = False
38
28
39 if not CELERY_ON:
29 if not CELERY_ON:
40 raise Exception('Please set use_celery = true in .ini config '
30 raise Exception('Please set use_celery = true in .ini config '
41 'file before running celeryd')
31 'file before running celeryd')
42 kallithea.CELERY_ON = CELERY_ON
32 kallithea.CELERY_ON = CELERY_ON
43
33
44 load_rcextensions(config['here'])
34 load_rcextensions(config['here'])
45 cmd = celerypylons.worker.worker(celerypylons.app.app_or_default())
35 cmd = celerypylons.worker.worker(celerypylons.app.app_or_default())
46 return cmd.run(**vars(self.options))
36
37 celery_args = args.celery_args
38 if '--' in celery_args:
39 celery_args.remove('--')
40
41 return cmd.run_from_argv('kallithea celery worker', celery_args)
42
43 def get_parser(self, prog_name):
44 parser = super(Command, self).get_parser(prog_name)
45
46 parser.add_argument('celery_args', nargs=argparse.REMAINDER,
47 help="Pass extra options to Celery after a '--' separator",
48 )
49
50 return parser
@@ -1,149 +1,142 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
14 """
15 kallithea.lib.paster_commands.cleanup
15 kallithea.lib.paster_commands.cleanup
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17
17
18 cleanup-repos paster command for Kallithea
18 cleanup-repos gearbox command for Kallithea
19
19
20
20
21 This file was forked by the Kallithea project in July 2014.
21 This file was forked by the Kallithea project in July 2014.
22 Original author and date, and relevant copyright and licensing information is below:
22 Original author and date, and relevant copyright and licensing information is below:
23 :created_on: Jul 14, 2012
23 :created_on: Jul 14, 2012
24 :author: marcink
24 :author: marcink
25 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 :copyright: (c) 2013 RhodeCode GmbH, and others.
26 :license: GPLv3, see LICENSE.md for more details.
26 :license: GPLv3, see LICENSE.md for more details.
27 """
27 """
28
28
29
29
30 import os
30 import os
31 import sys
31 import sys
32 import re
32 import re
33 import shutil
33 import shutil
34 import datetime
34 import datetime
35
35
36 from kallithea.lib.paster_commands.common import ask_ok, BasePasterCommand
36 from kallithea.lib.paster_commands.common import ask_ok, BasePasterCommand
37 from kallithea.lib.utils import REMOVED_REPO_PAT
37 from kallithea.lib.utils import REMOVED_REPO_PAT
38 from kallithea.lib.utils2 import safe_str
38 from kallithea.lib.utils2 import safe_str
39 from kallithea.model.db import Ui
39 from kallithea.model.db import Ui
40
40
41
41
42 class Command(BasePasterCommand):
42 class Command(BasePasterCommand):
43
43 """Kallithea: Cleanup of backup files of deleted repositories"""
44 max_args = 1
45 min_args = 1
46
47 usage = "CONFIG_FILE"
48 group_name = "Kallithea"
49 takes_config_file = -1
50 parser = BasePasterCommand.standard_parser(verbose=True)
51 summary = "Cleanup deleted repos"
52
44
53 def _parse_older_than(self, val):
45 def _parse_older_than(self, val):
54 regex = re.compile(r'((?P<days>\d+?)d)?((?P<hours>\d+?)h)?((?P<minutes>\d+?)m)?((?P<seconds>\d+?)s)?')
46 regex = re.compile(r'((?P<days>\d+?)d)?((?P<hours>\d+?)h)?((?P<minutes>\d+?)m)?((?P<seconds>\d+?)s)?')
55 parts = regex.match(val)
47 parts = regex.match(val)
56 if not parts:
48 if not parts:
57 return
49 return
58 parts = parts.groupdict()
50 parts = parts.groupdict()
59 time_params = {}
51 time_params = {}
60 for (name, param) in parts.iteritems():
52 for (name, param) in parts.iteritems():
61 if param:
53 if param:
62 time_params[name] = int(param)
54 time_params[name] = int(param)
63 return datetime.timedelta(**time_params)
55 return datetime.timedelta(**time_params)
64
56
65 def _extract_date(self, name):
57 def _extract_date(self, name):
66 """
58 """
67 Extract the date part from rm__<date> pattern of removed repos,
59 Extract the date part from rm__<date> pattern of removed repos,
68 and convert it to datetime object
60 and convert it to datetime object
69
61
70 :param name:
62 :param name:
71 """
63 """
72 date_part = name[4:19] # 4:19 since we don't parse milliseconds
64 date_part = name[4:19] # 4:19 since we don't parse milliseconds
73 return datetime.datetime.strptime(date_part, '%Y%m%d_%H%M%S')
65 return datetime.datetime.strptime(date_part, '%Y%m%d_%H%M%S')
74
66
75 def command(self):
67 def take_action(self, args):
76 #get SqlAlchemy session
77 self._init_session()
78
79 repos_location = Ui.get_repos_location()
68 repos_location = Ui.get_repos_location()
80 to_remove = []
69 to_remove = []
81 for dn_, dirs, f in os.walk(safe_str(repos_location)):
70 for dn_, dirs, f in os.walk(safe_str(repos_location)):
82 alldirs = list(dirs)
71 alldirs = list(dirs)
83 del dirs[:]
72 del dirs[:]
84 if ('.hg' in alldirs or
73 if ('.hg' in alldirs or
85 '.git' in alldirs or
74 '.git' in alldirs or
86 '.svn' in alldirs or
75 '.svn' in alldirs or
87 'objects' in alldirs and ('refs' in alldirs or 'packed-refs' in f)):
76 'objects' in alldirs and ('refs' in alldirs or 'packed-refs' in f)):
88 continue
77 continue
89 for loc in alldirs:
78 for loc in alldirs:
90 if REMOVED_REPO_PAT.match(loc):
79 if REMOVED_REPO_PAT.match(loc):
91 to_remove.append([os.path.join(dn_, loc),
80 to_remove.append([os.path.join(dn_, loc),
92 self._extract_date(loc)])
81 self._extract_date(loc)])
93 else:
82 else:
94 dirs.append(loc)
83 dirs.append(loc)
95 if dirs:
84 if dirs:
96 print 'Scanning: %s' % dn_
85 print 'Scanning: %s' % dn_
97
86
98 #filter older than (if present)!
87 #filter older than (if present)!
99 now = datetime.datetime.now()
88 now = datetime.datetime.now()
100 older_than = self.options.older_than
89 older_than = args.older_than
101 if older_than:
90 if older_than:
102 to_remove_filtered = []
91 to_remove_filtered = []
103 older_than_date = self._parse_older_than(older_than)
92 older_than_date = self._parse_older_than(older_than)
104 for name, date_ in to_remove:
93 for name, date_ in to_remove:
105 repo_age = now - date_
94 repo_age = now - date_
106 if repo_age > older_than_date:
95 if repo_age > older_than_date:
107 to_remove_filtered.append([name, date_])
96 to_remove_filtered.append([name, date_])
108
97
109 to_remove = to_remove_filtered
98 to_remove = to_remove_filtered
110 print 'Removing %s deleted repos older than %s (%s)' \
99 print 'Removing %s deleted repos older than %s (%s)' \
111 % (len(to_remove), older_than, older_than_date)
100 % (len(to_remove), older_than, older_than_date)
112 else:
101 else:
113 print 'Removing all %s deleted repos' % len(to_remove)
102 print 'Removing all %s deleted repos' % len(to_remove)
114 if self.options.dont_ask or not to_remove:
103 if args.dont_ask or not to_remove:
115 # don't ask just remove !
104 # don't ask just remove !
116 remove = True
105 remove = True
117 else:
106 else:
118 remove = ask_ok('the following repositories will be deleted completely:\n%s\n'
107 remove = ask_ok('the following repositories will be deleted completely:\n%s\n'
119 'are you sure you want to remove them [y/n]?'
108 'are you sure you want to remove them [y/n]?'
120 % '\n'.join(['%s removed on %s' % (safe_str(x[0]), safe_str(x[1]))
109 % '\n'.join(['%s removed on %s' % (safe_str(x[0]), safe_str(x[1]))
121 for x in to_remove]))
110 for x in to_remove]))
122
111
123 if remove:
112 if remove:
124 for path, date_ in to_remove:
113 for path, date_ in to_remove:
125 print 'Removing repository %s' % path
114 print 'Removing repository %s' % path
126 shutil.rmtree(path)
115 shutil.rmtree(path)
127 else:
116 else:
128 print 'Nothing done, exiting...'
117 print 'Nothing done, exiting...'
129
118
130 def update_parser(self):
119 def get_parser(self, prog_name):
131 self.parser.add_option(
120 parser = super(Command, self).get_parser(prog_name)
121
122 parser.add_argument(
132 '--older-than',
123 '--older-than',
133 action='store',
124 action='store',
134 dest='older_than',
125 dest='older_than',
135 help=("only remove repos that have been removed "
126 help=("only remove repos that have been removed "
136 "at least given time ago. "
127 "at least given time ago. "
137 "The default is to remove all removed repositories. "
128 "The default is to remove all removed repositories. "
138 "Possible suffixes: "
129 "Possible suffixes: "
139 "d (days), h (hours), m (minutes), s (seconds). "
130 "d (days), h (hours), m (minutes), s (seconds). "
140 "For example --older-than=30d deletes repositories "
131 "For example --older-than=30d deletes repositories "
141 "removed more than 30 days ago.")
132 "removed more than 30 days ago.")
142 )
133 )
143
134
144 self.parser.add_option(
135 parser.add_argument(
145 '--dont-ask',
136 '--dont-ask',
146 action="store_true",
137 action="store_true",
147 dest="dont_ask",
138 dest="dont_ask",
148 help="remove repositories without asking for confirmation."
139 help="remove repositories without asking for confirmation."
149 )
140 )
141
142 return parser
@@ -1,107 +1,108 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
14 """
15 kallithea.lib.paster_commands.common
15 kallithea.lib.paster_commands.common
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17
17
18 Common code for Paster commands.
18 Common code for gearbox commands.
19
19
20 This file was forked by the Kallithea project in July 2014.
20 This file was forked by the Kallithea project in July 2014.
21 Original author and date, and relevant copyright and licensing information is below:
21 Original author and date, and relevant copyright and licensing information is below:
22 :created_on: Apr 18, 2010
22 :created_on: Apr 18, 2010
23 :author: marcink
23 :author: marcink
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 :license: GPLv3, see LICENSE.md for more details.
25 :license: GPLv3, see LICENSE.md for more details.
26 """
26 """
27
27
28 import os
28 import os
29 import logging
29 import sys
30 import logging.config
30
31
31 import paste
32 import paste.deploy
32 from paste.script.command import Command, BadCommand
33 import gearbox.command
33
34 from kallithea.lib.utils import setup_cache_regions
35
34
36
35
37 def ask_ok(prompt, retries=4, complaint='Yes or no please!'):
36 def ask_ok(prompt, retries=4, complaint='Yes or no please!'):
38 while True:
37 while True:
39 ok = raw_input(prompt)
38 ok = raw_input(prompt)
40 if ok in ('y', 'ye', 'yes'):
39 if ok in ('y', 'ye', 'yes'):
41 return True
40 return True
42 if ok in ('n', 'no', 'nop', 'nope'):
41 if ok in ('n', 'no', 'nop', 'nope'):
43 return False
42 return False
44 retries = retries - 1
43 retries = retries - 1
45 if retries < 0:
44 if retries < 0:
46 raise IOError
45 raise IOError
47 print complaint
46 print complaint
48
47
49
48
50 class BasePasterCommand(Command):
49 class BasePasterCommand(gearbox.command.Command):
51 """
50 """
52 Abstract Base Class for paster commands.
51 Abstract Base Class for gearbox commands.
53 """
52 """
54 min_args = 1
53
55 min_args_error = "Please provide a paster config file as an argument."
54 # override to control how much get_parser and run should do:
56 takes_config_file = 1
55 takes_config_file = True
57 requires_config_file = True
56 requires_db_session = True
58
57
59 def run(self, args):
58 def run(self, args):
60 """
59 """
61 Overrides Command.run
60 Overrides Command.run
62
61
63 Checks for a config file argument and loads it.
62 Checks for a config file argument and loads it.
64 """
63 """
65 if len(args) < self.min_args:
64 if self.takes_config_file:
66 raise BadCommand(
65 self._bootstrap_config(args.config_file)
67 self.min_args_error % {'min_args': self.min_args,
66 if self.requires_db_session:
68 'actual_args': len(args)})
67 self._init_session()
69
68
70 # Decrement because we're going to lob off the first argument.
69 return super(BasePasterCommand, self).run(args)
71 # @@ This is hacky
70
72 self.min_args -= 1
71 def get_parser(self, prog_name):
73 self.bootstrap_config(args[0])
72 parser = super(BasePasterCommand, self).get_parser(prog_name)
74 self.update_parser()
75 return super(BasePasterCommand, self).run(args[1:])
76
73
77 def update_parser(self):
74 if self.takes_config_file:
75 parser.add_argument("-c", "--config",
76 help='Kallithea .ini file with configuration of database etc',
77 dest='config_file', required=True)
78
79 return parser
80
81 def _bootstrap_config(self, config_file):
78 """
82 """
79 Abstract method. Allows for the class's parser to be updated
83 Read the config file and initialize logging and the application.
80 before the superclass's `run` method is called. Necessary to
81 allow options/arguments to be passed through to the underlying
82 celery command.
83 """
84 raise NotImplementedError("Abstract Method.")
85
86 def bootstrap_config(self, conf):
87 """
88 Loads the app configuration.
89 """
84 """
90 from tg import config as pylonsconfig
85 from tg import config as pylonsconfig
91
86
92 self.path_to_ini_file = os.path.realpath(conf)
87 path_to_ini_file = os.path.realpath(config_file)
93 conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
88 conf = paste.deploy.appconfig('config:' + path_to_ini_file)
89 logging.config.fileConfig(path_to_ini_file)
94 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
90 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
95
91
96 def _init_session(self):
92 def _init_session(self):
97 """
93 """
98 Inits SqlAlchemy Session
94 Initialize SqlAlchemy Session from global config.
99 """
95 """
100 logging.config.fileConfig(self.path_to_ini_file)
101
96
102 from tg import config
97 from tg import config
103 from kallithea.model.base import init_model
98 from kallithea.model.base import init_model
104 from kallithea.lib.utils2 import engine_from_config
99 from kallithea.lib.utils2 import engine_from_config
100 from kallithea.lib.utils import setup_cache_regions
105 setup_cache_regions(config)
101 setup_cache_regions(config)
106 engine = engine_from_config(config, 'sqlalchemy.')
102 engine = engine_from_config(config, 'sqlalchemy.')
107 init_model(engine)
103 init_model(engine)
104
105 def error(self, msg, exitcode=1):
106 """Write error message and exit"""
107 sys.stderr.write('%s\n' % msg)
108 raise SystemExit(exitcode)
@@ -1,104 +1,99 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
14 """
15 kallithea.lib.paster_commands.install_iis
15 kallithea.lib.paster_commands.install_iis
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17
17
18 IIS installation tools for Kallithea
18 IIS installation tools for Kallithea
19 """
19 """
20
20
21
21
22 import os
22 import os
23 import sys
23 import sys
24 from paste.script.appinstall import AbstractInstallCommand
24 from paste.script.appinstall import AbstractInstallCommand
25 from paste.script.command import BadCommand
25
26 from kallithea.lib.paster_commands.common import BasePasterCommand
26
27
27
28
28 class Command(AbstractInstallCommand):
29 class Command(BasePasterCommand):
29 default_verbosity = 1
30 '''Kallithea: Install into IIS using isapi-wsgi'''
30 max_args = 1
31 min_args = 1
32 summary = 'Setup IIS given a config file'
33 usage = 'CONFIG_FILE'
34
31
35 description = '''
32 requires_db_session = False
36 Script for installing into IIS using isapi-wsgi.
37 '''
38 parser = AbstractInstallCommand.standard_parser(
39 simulate=True, quiet=True, interactive=True)
40 parser.add_option('--virtualdir',
41 action='store',
42 dest='virtualdir',
43 default='/',
44 help='The virtual folder to install into on IIS')
45
33
46 def command(self):
34 def take_action(self, args):
47 config_spec = self.args[0]
35 config_file = os.path.abspath(args.config_file)
48 if not config_spec.startswith('config:'):
49 config_spec = 'config:' + config_spec
50 config_file = config_spec[len('config:'):].split('#', 1)[0]
51 config_file = os.path.join(os.getcwd(), config_file)
52 try:
36 try:
53 import isapi_wsgi
37 import isapi_wsgi
54 except ImportError:
38 except ImportError:
55 raise BadCommand('missing requirement: isapi-wsgi not installed')
39 self.error('missing requirement: isapi-wsgi not installed')
56
40
57 file = '''\
41 file = '''\
58 # Created by Kallithea install_iis
42 # Created by Kallithea install_iis
59 import sys
43 import sys
60
44
61 if hasattr(sys, "isapidllhandle"):
45 if hasattr(sys, "isapidllhandle"):
62 import win32traceutil
46 import win32traceutil
63
47
64 import isapi_wsgi
48 import isapi_wsgi
65 import os
49 import os
66
50
67 def __ExtensionFactory__():
51 def __ExtensionFactory__():
68 from paste.deploy import loadapp
52 from paste.deploy import loadapp
69 from paste.script.util.logging_config import fileConfig
53 from paste.script.util.logging_config import fileConfig
70 fileConfig('%(inifile)s')
54 fileConfig('%(inifile)s')
71 application = loadapp('config:%(inifile)s')
55 application = loadapp('config:%(inifile)s')
72
56
73 def app(environ, start_response):
57 def app(environ, start_response):
74 user = environ.get('REMOTE_USER', None)
58 user = environ.get('REMOTE_USER', None)
75 if user is not None:
59 if user is not None:
76 os.environ['REMOTE_USER'] = user
60 os.environ['REMOTE_USER'] = user
77 return application(environ, start_response)
61 return application(environ, start_response)
78
62
79 return isapi_wsgi.ISAPIThreadPoolHandler(app)
63 return isapi_wsgi.ISAPIThreadPoolHandler(app)
80
64
81 if __name__=='__main__':
65 if __name__=='__main__':
82 from isapi.install import *
66 from isapi.install import *
83 params = ISAPIParameters()
67 params = ISAPIParameters()
84 sm = [ScriptMapParams(Extension="*", Flags=0)]
68 sm = [ScriptMapParams(Extension="*", Flags=0)]
85 vd = VirtualDirParameters(Name="%(virtualdir)s",
69 vd = VirtualDirParameters(Name="%(virtualdir)s",
86 Description = "Kallithea",
70 Description = "Kallithea",
87 ScriptMaps = sm,
71 ScriptMaps = sm,
88 ScriptMapUpdate = "replace")
72 ScriptMapUpdate = "replace")
89 params.VirtualDirs = [vd]
73 params.VirtualDirs = [vd]
90 HandleCommandLine(params)
74 HandleCommandLine(params)
91 '''
75 '''
92
76
93 outdata = file % {
77 outdata = file % {
94 'inifile': config_file.replace('\\', '\\\\'),
78 'inifile': config_file.replace('\\', '\\\\'),
95 'virtualdir': self.options.virtualdir
79 'virtualdir': args.virtualdir,
96 }
80 }
97
81
98 dispatchfile = os.path.join(os.getcwd(), 'dispatch.py')
82 dispatchfile = os.path.join(os.getcwd(), 'dispatch.py')
99 self.ensure_file(dispatchfile, outdata, False)
83 self.ensure_file(dispatchfile, outdata, False)
100 print 'Generating %s' % (dispatchfile,)
84 print 'Generating %s' % (dispatchfile,)
101
85
102 print ('Run \'python "%s" install\' with administrative privileges '
86 print ('Run \'python "%s" install\' with administrative privileges '
103 'to generate the _dispatch.dll file and install it into the '
87 'to generate the _dispatch.dll file and install it into the '
104 'default web site') % (dispatchfile,)
88 'default web site') % (dispatchfile,)
89
90 def get_parser(self, prog_name):
91 parser = super(Command, self).get_parser(prog_name)
92
93 parser.add_argument('--virtualdir',
94 action='store',
95 dest='virtualdir',
96 default='/',
97 help='The virtual folder to install into on IIS')
98
99 return parser
@@ -1,67 +1,53 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
14 """
15 kallithea.lib.paster_commands.ishell
15 kallithea.lib.paster_commands.ishell
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17
17
18 interactive shell paster command for Kallithea
18 interactive shell gearbox command for Kallithea
19
19
20 This file was forked by the Kallithea project in July 2014.
20 This file was forked by the Kallithea project in July 2014.
21 Original author and date, and relevant copyright and licensing information is below:
21 Original author and date, and relevant copyright and licensing information is below:
22 :created_on: Apr 4, 2013
22 :created_on: Apr 4, 2013
23 :author: marcink
23 :author: marcink
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 :license: GPLv3, see LICENSE.md for more details.
25 :license: GPLv3, see LICENSE.md for more details.
26 """
26 """
27
27
28
28
29 import os
29 import os
30 import sys
30 import sys
31
31
32 # imports, used in IPython shell
32 # imports, used in IPython shell
33 import time
33 import time
34 import shutil
34 import shutil
35 import datetime
35 import datetime
36 from kallithea.model.db import *
36 from kallithea.model.db import *
37
37
38 from kallithea.lib.paster_commands.common import BasePasterCommand
38 from kallithea.lib.paster_commands.common import BasePasterCommand
39
39
40
40
41 class Command(BasePasterCommand):
41 class Command(BasePasterCommand):
42
42 "Kallithea: Interactive Python shell"
43 max_args = 1
44 min_args = 1
45
43
46 usage = "CONFIG_FILE"
44 def take_action(self, args):
47 group_name = "Kallithea"
48 takes_config_file = -1
49 parser = BasePasterCommand.standard_parser(verbose=True)
50 summary = "Interactive shell"
51
52 def command(self):
53 #get SqlAlchemy session
54 self._init_session()
55
56 try:
45 try:
57 from IPython import embed
46 from IPython import embed
58 from IPython.config.loader import Config
47 from IPython.config.loader import Config
59 cfg = Config()
48 cfg = Config()
60 cfg.InteractiveShellEmbed.confirm_exit = False
49 cfg.InteractiveShellEmbed.confirm_exit = False
61 embed(config=cfg, banner1="Kallithea IShell.")
50 embed(config=cfg, banner1="Kallithea IShell.")
62 except ImportError:
51 except ImportError:
63 print 'Kallithea ishell requires the IPython Python package'
52 print 'Kallithea ishell requires the IPython Python package'
64 sys.exit(-1)
53 sys.exit(-1)
65
66 def update_parser(self):
67 pass
@@ -1,106 +1,100 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
14 """
15 kallithea.lib.paster_commands.make_index
15 kallithea.lib.paster_commands.make_index
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17
17
18 make-index paster command for Kallithea
18 make-index gearbox command for Kallithea
19
19
20 This file was forked by the Kallithea project in July 2014.
20 This file was forked by the Kallithea project in July 2014.
21 Original author and date, and relevant copyright and licensing information is below:
21 Original author and date, and relevant copyright and licensing information is below:
22 :created_on: Aug 17, 2010
22 :created_on: Aug 17, 2010
23 :author: marcink
23 :author: marcink
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 :license: GPLv3, see LICENSE.md for more details.
25 :license: GPLv3, see LICENSE.md for more details.
26 """
26 """
27
27
28
28
29 import os
29 import os
30 import sys
30 import sys
31 from os.path import dirname
31 from os.path import dirname
32
32
33 from string import strip
33 from string import strip
34 from kallithea.model.repo import RepoModel
34 from kallithea.model.repo import RepoModel
35 from kallithea.lib.paster_commands.common import BasePasterCommand
35 from kallithea.lib.paster_commands.common import BasePasterCommand
36 from kallithea.lib.utils import load_rcextensions
36 from kallithea.lib.utils import load_rcextensions
37
37
38
38
39 class Command(BasePasterCommand):
39 class Command(BasePasterCommand):
40
40 "Kallithea: Create or update full text search index"
41 max_args = 1
42 min_args = 1
43
41
44 usage = "CONFIG_FILE"
42 def take_action(self, args):
45 group_name = "Kallithea"
43 from pylons import config
46 takes_config_file = -1
47 parser = BasePasterCommand.standard_parser(verbose=True)
48 summary = "Creates or updates full text search index"
49
50 def command(self):
51 #get SqlAlchemy session
52 self._init_session()
53 from tg import config
54 index_location = config['index_dir']
44 index_location = config['index_dir']
55 load_rcextensions(config['here'])
45 load_rcextensions(config['here'])
56
46
57 repo_location = self.options.repo_location \
47 repo_location = args.repo_location \
58 if self.options.repo_location else RepoModel().repos_path
48 if args.repo_location else RepoModel().repos_path
59 repo_list = map(strip, self.options.repo_list.split(',')) \
49 repo_list = map(strip, args.repo_list.split(',')) \
60 if self.options.repo_list else None
50 if args.repo_list else None
61
51
62 repo_update_list = map(strip, self.options.repo_update_list.split(',')) \
52 repo_update_list = map(strip, args.repo_update_list.split(',')) \
63 if self.options.repo_update_list else None
53 if args.repo_update_list else None
64
54
65 #======================================================================
55 #======================================================================
66 # WHOOSH DAEMON
56 # WHOOSH DAEMON
67 #======================================================================
57 #======================================================================
68 from kallithea.lib.pidlock import LockHeld, DaemonLock
58 from kallithea.lib.pidlock import LockHeld, DaemonLock
69 from kallithea.lib.indexers.daemon import WhooshIndexingDaemon
59 from kallithea.lib.indexers.daemon import WhooshIndexingDaemon
70 try:
60 try:
71 l = DaemonLock(file_=os.path.join(dirname(dirname(index_location)),
61 l = DaemonLock(file_=os.path.join(dirname(dirname(index_location)),
72 'make_index.lock'))
62 'make_index.lock'))
73 WhooshIndexingDaemon(index_location=index_location,
63 WhooshIndexingDaemon(index_location=index_location,
74 repo_location=repo_location,
64 repo_location=repo_location,
75 repo_list=repo_list,
65 repo_list=repo_list,
76 repo_update_list=repo_update_list) \
66 repo_update_list=repo_update_list) \
77 .run(full_index=self.options.full_index)
67 .run(full_index=args.full_index)
78 l.release()
68 l.release()
79 except LockHeld:
69 except LockHeld:
80 sys.exit(1)
70 sys.exit(1)
81
71
82 def update_parser(self):
72 def get_parser(self, prog_name):
83 self.parser.add_option('--repo-location',
73 parser = super(Command, self).get_parser(prog_name)
74
75 parser.add_argument('--repo-location',
84 action='store',
76 action='store',
85 dest='repo_location',
77 dest='repo_location',
86 help="Specifies repositories location to index OPTIONAL",
78 help="Specifies repositories location to index OPTIONAL",
87 )
79 )
88 self.parser.add_option('--index-only',
80 parser.add_argument('--index-only',
89 action='store',
81 action='store',
90 dest='repo_list',
82 dest='repo_list',
91 help="Specifies a comma separated list of repositories "
83 help="Specifies a comma separated list of repositories "
92 "to build index on. If not given all repositories "
84 "to build index on. If not given all repositories "
93 "are scanned for indexing. OPTIONAL",
85 "are scanned for indexing. OPTIONAL",
94 )
86 )
95 self.parser.add_option('--update-only',
87 parser.add_argument('--update-only',
96 action='store',
88 action='store',
97 dest='repo_update_list',
89 dest='repo_update_list',
98 help="Specifies a comma separated list of repositories "
90 help="Specifies a comma separated list of repositories "
99 "to re-build index on. OPTIONAL",
91 "to re-build index on. OPTIONAL",
100 )
92 )
101 self.parser.add_option('-f',
93 parser.add_argument('-f',
102 action='store_true',
94 action='store_true',
103 dest='full_index',
95 dest='full_index',
104 help="Specifies that index should be made full i.e"
96 help="Specifies that index should be made full i.e"
105 " destroy old and build from scratch",
97 " destroy old and build from scratch",
106 default=False)
98 default=False)
99
100 return parser
@@ -1,75 +1,66 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
14 """
15 kallithea.lib.paster_commands.make_rcextensions
15 kallithea.lib.paster_commands.make_rcextensions
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17
17
18 make-rcext paster command for Kallithea
18 make-rcext gearbox command for Kallithea
19
19
20 This file was forked by the Kallithea project in July 2014.
20 This file was forked by the Kallithea project in July 2014.
21 Original author and date, and relevant copyright and licensing information is below:
21 Original author and date, and relevant copyright and licensing information is below:
22 :created_on: Mar 6, 2012
22 :created_on: Mar 6, 2012
23 :author: marcink
23 :author: marcink
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 :license: GPLv3, see LICENSE.md for more details.
25 :license: GPLv3, see LICENSE.md for more details.
26 """
26 """
27
27
28
28
29 import os
29 import os
30 import sys
30 import sys
31 import pkg_resources
31 import pkg_resources
32
32
33 from kallithea.lib.paster_commands.common import ask_ok, BasePasterCommand
33 from kallithea.lib.paster_commands.common import ask_ok, BasePasterCommand
34
34
35
35
36 class Command(BasePasterCommand):
36 class Command(BasePasterCommand):
37
37 """Kallithea: Write template file for extending Kallithea in Python
38 max_args = 1
39 min_args = 1
40
38
41 group_name = "Kallithea"
42 takes_config_file = -1
43 parser = BasePasterCommand.standard_parser(verbose=True)
44 summary = "Write template file for extending Kallithea in Python."
45 usage = "CONFIG_FILE"
46 description = '''\
47 A rcextensions directory with a __init__.py file will be created next to
39 A rcextensions directory with a __init__.py file will be created next to
48 the ini file. Local customizations in that file will survive upgrades.
40 the ini file. Local customizations in that file will survive upgrades.
49 The file contains instructions on how it can be customized.
41 The file contains instructions on how it can be customized.
50 '''
42 """
51
43
52 def command(self):
44 takes_config_file = False
53 from tg import config
45
46 def take_action(self, args):
47 from pylons import config
54
48
55 here = config['here']
49 here = config['here']
56 content = pkg_resources.resource_string(
50 content = pkg_resources.resource_string(
57 'kallithea', os.path.join('config', 'rcextensions', '__init__.py')
51 'kallithea', os.path.join('config', 'rcextensions', '__init__.py')
58 )
52 )
59 ext_file = os.path.join(here, 'rcextensions', '__init__.py')
53 ext_file = os.path.join(here, 'rcextensions', '__init__.py')
60 if os.path.exists(ext_file):
54 if os.path.exists(ext_file):
61 msg = ('Extension file already exists, do you want '
55 msg = ('Extension file already exists, do you want '
62 'to overwrite it ? [y/n]')
56 'to overwrite it ? [y/n]')
63 if not ask_ok(msg):
57 if not ask_ok(msg):
64 print 'Nothing done, exiting...'
58 print 'Nothing done, exiting...'
65 return
59 return
66
60
67 dirname = os.path.dirname(ext_file)
61 dirname = os.path.dirname(ext_file)
68 if not os.path.isdir(dirname):
62 if not os.path.isdir(dirname):
69 os.makedirs(dirname)
63 os.makedirs(dirname)
70 with open(ext_file, 'wb') as f:
64 with open(ext_file, 'wb') as f:
71 f.write(content)
65 f.write(content)
72 print 'Wrote new extensions file to %s' % ext_file
66 print 'Wrote new extensions file to %s' % ext_file
73
74 def update_parser(self):
75 pass
@@ -1,70 +1,68 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
14 """
15 kallithea.lib.paster_commands.repo_scan
15 kallithea.lib.paster_commands.repo_scan
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17
17
18 repo-scan paster command for Kallithea
18 repo-scan gearbox command for Kallithea
19
19
20 This file was forked by the Kallithea project in July 2014.
20 This file was forked by the Kallithea project in July 2014.
21 Original author and date, and relevant copyright and licensing information is below:
21 Original author and date, and relevant copyright and licensing information is below:
22 :created_on: Feb 9, 2013
22 :created_on: Feb 9, 2013
23 :author: marcink
23 :author: marcink
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 :license: GPLv3, see LICENSE.md for more details.
25 :license: GPLv3, see LICENSE.md for more details.
26 """
26 """
27
27
28
28
29 import os
29 import os
30 import sys
30 import sys
31
31
32 from kallithea.model.scm import ScmModel
32 from kallithea.model.scm import ScmModel
33 from kallithea.lib.paster_commands.common import BasePasterCommand
33 from kallithea.lib.paster_commands.common import BasePasterCommand
34 from kallithea.lib.utils import repo2db_mapper
34 from kallithea.lib.utils import repo2db_mapper
35
35
36
36
37 class Command(BasePasterCommand):
37 class Command(BasePasterCommand):
38
38 """Kallithea: Scan file system for repositories
39 max_args = 1
40 min_args = 1
41
39
42 usage = "CONFIG_FILE"
40 Search under the repository root configured in the database,
43 group_name = "Kallithea"
41 all new repositories, and report missing ones with an option of removing them.
44 takes_config_file = -1
42 """
45 parser = BasePasterCommand.standard_parser(verbose=True)
46 summary = "Rescan default location for new repositories"
47
43
48 def command(self):
44 def take_action(self, args):
49 #get SqlAlchemy session
45 rm_obsolete = args.delete_obsolete
50 self._init_session()
51 rm_obsolete = self.options.delete_obsolete
52 print 'Now scanning root location for new repos ...'
46 print 'Now scanning root location for new repos ...'
53 added, removed = repo2db_mapper(ScmModel().repo_scan(),
47 added, removed = repo2db_mapper(ScmModel().repo_scan(),
54 remove_obsolete=rm_obsolete)
48 remove_obsolete=rm_obsolete)
55 added = ', '.join(added) or '-'
49 added = ', '.join(added) or '-'
56 removed = ', '.join(removed) or '-'
50 removed = ', '.join(removed) or '-'
57 print 'Scan completed.'
51 print 'Scan completed.'
58 print 'Added: %s' % added
52 print 'Added: %s' % added
59 if rm_obsolete:
53 if rm_obsolete:
60 print 'Removed: %s' % removed
54 print 'Removed: %s' % removed
61 else:
55 else:
62 print 'Missing: %s' % removed
56 print 'Missing: %s' % removed
63
57
64 def update_parser(self):
58 def get_parser(self, prog_name):
65 self.parser.add_option(
59 parser = super(Command, self).get_parser(prog_name)
60
61 parser.add_argument(
66 '--delete-obsolete',
62 '--delete-obsolete',
67 action='store_true',
63 action='store_true',
68 help="Use this flag do delete repositories that are "
64 help="Use this flag do delete repositories that are "
69 "present in Kallithea database but not on the filesystem",
65 "present in Kallithea database but not on the filesystem",
70 )
66 )
67
68 return parser
@@ -1,126 +1,107 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
14 """
15 kallithea.lib.paster_commands.setup_db
15 kallithea.lib.paster_commands.setup_db
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17
17
18 Databaset setup paster command for Kallithea
18 Databaset setup gearbox command for Kallithea
19 """
19 """
20
20
21
21
22 import os
22 import os
23 import sys
23 import sys
24 from paste.script.appinstall import AbstractInstallCommand
24 import paste.deploy
25 from paste.script.command import BadCommand
25
26 from paste.deploy import appconfig
26 from kallithea.lib.db_manage import DbManage
27 from kallithea.lib.paster_commands.common import BasePasterCommand
28 from kallithea.model.meta import Session
27
29
28
30
29 class Command(AbstractInstallCommand):
31 # This is almost like SetupAppCommand ... but we have to pass options and it is
32 # thus simpler to drop websetup and reimplement everything
33 class Command(BasePasterCommand):
34 """Kallithea: Configure the database specified in the .ini file
30
35
31 default_verbosity = 1
32 max_args = 1
33 min_args = 1
34 summary = "Setup an application, given a config file"
35 usage = "CONFIG_FILE"
36 group_name = "Kallithea"
37
38 description = """\
39 Setup Kallithea according to its configuration file. This is
36 Setup Kallithea according to its configuration file. This is
40 the second part of a two-phase web application installation
37 the second part of a two-phase web application installation
41 process (the first phase is prepare-app). The setup process
38 process (the first phase is prepare-app). The setup process
42 consist of things like setting up databases, creating super user
39 consist of things like setting up databases and creating the admin user
43 """
40 """
44
41
45 parser = AbstractInstallCommand.standard_parser(
42 def get_description(self):
46 simulate=True, quiet=True, interactive=True)
43 return self.__doc__.splitlines()[0]
47 parser.add_option('--user',
44
45 requires_db_session = False # only available after this command has been run
46
47 def get_parser(self, prog_name):
48 parser = super(Command, self).get_parser(prog_name)
49
50 parser.add_argument('--user',
48 action='store',
51 action='store',
49 dest='username',
52 dest='username',
50 default=None,
53 default=None,
51 help='Admin Username')
54 help='Admin Username')
52 parser.add_option('--email',
55 parser.add_argument('--email',
53 action='store',
56 action='store',
54 dest='email',
57 dest='email',
55 default=None,
58 default=None,
56 help='Admin Email')
59 help='Admin Email')
57 parser.add_option('--password',
60 parser.add_argument('--password',
58 action='store',
61 action='store',
59 dest='password',
62 dest='password',
60 default=None,
63 default=None,
61 help='Admin password min 6 chars')
64 help='Admin password min 6 chars')
62 parser.add_option('--repos',
65 parser.add_argument('--repos',
63 action='store',
66 action='store',
64 dest='repos_location',
67 dest='repos_location',
65 default=None,
68 default=None,
66 help='Absolute path to repositories location')
69 help='Absolute path to repositories location')
67 parser.add_option('--name',
70 parser.add_argument('--force-yes',
68 action='store',
69 dest='section_name',
70 default=None,
71 help='The name of the section to set up (default: app:main)')
72 parser.add_option('--force-yes',
73 action='store_true',
71 action='store_true',
74 dest='force_ask',
72 dest='force_ask',
75 default=None,
73 default=None,
76 help='Force yes to every question')
74 help='Force yes to every question')
77 parser.add_option('--force-no',
75 parser.add_argument('--force-no',
78 action='store_false',
76 action='store_false',
79 dest='force_ask',
77 dest='force_ask',
80 default=None,
78 default=None,
81 help='Force no to every question')
79 help='Force no to every question')
82 parser.add_option('--public-access',
80 parser.add_argument('--public-access',
83 action='store_true',
81 action='store_true',
84 dest='public_access',
82 dest='public_access',
85 default=None,
83 default=None,
86 help='Enable public access on this installation (default)')
84 help='Enable public access on this installation (default)')
87 parser.add_option('--no-public-access',
85 parser.add_argument('--no-public-access',
88 action='store_false',
86 action='store_false',
89 dest='public_access',
87 dest='public_access',
90 default=None,
88 default=None,
91 help='Disable public access on this installation ')
89 help='Disable public access on this installation ')
92
90
93 def command(self):
91 return parser
94 config_spec = self.args[0]
92
95 section = self.options.section_name
93 def take_action(self, opts):
96 if section is None:
94 path_to_ini_file = os.path.realpath(opts.config_file)
97 if '#' in config_spec:
95 conf = paste.deploy.appconfig('config:' + path_to_ini_file)
98 config_spec, section = config_spec.split('#', 1)
96
99 else:
97 dbconf = conf['sqlalchemy.url']
100 section = 'main'
98 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=conf['here'],
101 if not ':' in section:
99 tests=False, cli_args=vars(opts))
102 plain_section = section
100 dbmanage.create_tables(override=True)
103 section = 'app:' + section
101 opts = dbmanage.config_prompt(None)
104 else:
102 dbmanage.create_settings(opts)
105 plain_section = section.split(':', 1)[0]
103 dbmanage.create_default_user()
106 if not config_spec.startswith('config:'):
104 dbmanage.admin_prompt()
107 config_spec = 'config:' + config_spec
105 dbmanage.create_permissions()
108 if plain_section != 'main':
106 dbmanage.populate_default_permissions()
109 config_spec += '#' + plain_section
107 Session().commit()
110 config_file = config_spec[len('config:'):].split('#', 1)[0]
111 config_file = os.path.join(os.getcwd(), config_file)
112 self.logging_file_config(config_file)
113 conf = appconfig(config_spec, relative_to=os.getcwd())
114 ep_name = conf.context.entry_point_name
115 ep_group = conf.context.protocol
116 dist = conf.context.distribution
117 if dist is None:
118 raise BadCommand(
119 "The section %r is not the application (probably a filter). "
120 "You should add #section_name, where section_name is the "
121 "section that configures your application" % plain_section)
122 installer = self.get_installer(dist, ep_group, ep_name)
123 installer.setup_config(
124 self, config_file, section, self.sysconfig_install_vars(installer))
125 self.call_sysconfig_functions(
126 'post_setup_hook', installer, config_file)
@@ -1,84 +1,76 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
14 """
15 kallithea.lib.paster_commands.update_repoinfo
15 kallithea.lib.paster_commands.update_repoinfo
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17
17
18 update-repoinfo paster command for Kallithea
18 update-repoinfo gearbox command for Kallithea
19
19
20 This file was forked by the Kallithea project in July 2014.
20 This file was forked by the Kallithea project in July 2014.
21 Original author and date, and relevant copyright and licensing information is below:
21 Original author and date, and relevant copyright and licensing information is below:
22 :created_on: Jul 14, 2012
22 :created_on: Jul 14, 2012
23 :author: marcink
23 :author: marcink
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
24 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 :license: GPLv3, see LICENSE.md for more details.
25 :license: GPLv3, see LICENSE.md for more details.
26 """
26 """
27
27
28
28
29 import os
29 import os
30 import sys
30 import sys
31 import string
31 import string
32
32
33 from kallithea.lib.paster_commands.common import BasePasterCommand
33 from kallithea.lib.paster_commands.common import BasePasterCommand
34 from kallithea.lib.utils2 import safe_unicode
34 from kallithea.lib.utils2 import safe_unicode
35 from kallithea.model.db import Repository
35 from kallithea.model.db import Repository
36 from kallithea.model.repo import RepoModel
36 from kallithea.model.repo import RepoModel
37 from kallithea.model.meta import Session
37 from kallithea.model.meta import Session
38
38
39
39
40 class Command(BasePasterCommand):
40 class Command(BasePasterCommand):
41
41 "Kallithea: Update database cache of repository data"
42 max_args = 1
43 min_args = 1
44
42
45 usage = "CONFIG_FILE"
43 def take_action(self, args):
46 group_name = "Kallithea"
44 if args.repo_update_list is None:
47 takes_config_file = -1
48 parser = BasePasterCommand.standard_parser(verbose=True)
49 summary = "Updates repositories caches for last changeset"
50
51 def command(self):
52 #get SqlAlchemy session
53 self._init_session()
54
55
56 if self.options.repo_update_list is None:
57 repo_list = Repository.query().all()
45 repo_list = Repository.query().all()
58 else:
46 else:
59 repo_names = [safe_unicode(n.strip())
47 repo_names = [safe_unicode(n.strip())
60 for n in self.options.repo_update_list.split(',')]
48 for n in args.repo_update_list.split(',')]
61 repo_list = list(Repository.query()
49 repo_list = list(Repository.query()
62 .filter(Repository.repo_name.in_(repo_names)))
50 .filter(Repository.repo_name.in_(repo_names)))
63 for repo in repo_list:
51 for repo in repo_list:
64 repo.update_changeset_cache()
52 repo.update_changeset_cache()
65 Session().commit()
53 Session().commit()
66
54
67 if self.options.invalidate_cache:
55 if args.invalidate_cache:
68 for r in repo_list:
56 for r in repo_list:
69 r.set_invalidate()
57 r.set_invalidate()
70 print 'Updated repo info and invalidated cache for %s repositories' % (len(repo_list))
58 print 'Updated repo info and invalidated cache for %s repositories' % (len(repo_list))
71 else:
59 else:
72 print 'Updated repo info for %s repositories' % (len(repo_list))
60 print 'Updated repo info for %s repositories' % (len(repo_list))
73
61
74 def update_parser(self):
62 def get_parser(self, prog_name):
75 self.parser.add_option('--update-only',
63 parser = super(Command, self).get_parser(prog_name)
64
65 parser.add_argument('--update-only',
76 action='store',
66 action='store',
77 dest='repo_update_list',
67 dest='repo_update_list',
78 help="Specifies a comma separated list of repositories "
68 help="Specifies a comma separated list of repositories "
79 "to update last commit info for. OPTIONAL")
69 "to update last commit info for. OPTIONAL")
80 self.parser.add_option('--invalidate-cache',
70 parser.add_argument('--invalidate-cache',
81 action='store_true',
71 action='store_true',
82 dest='invalidate_cache',
72 dest='invalidate_cache',
83 help="Trigger cache invalidation event for repos. "
73 help="Trigger cache invalidation event for repos. "
84 "OPTIONAL")
74 "OPTIONAL")
75
76 return parser
@@ -1,562 +1,562 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 """
14 """
15 kallithea.tests.other.manual_test_vcs_operations
15 kallithea.tests.other.manual_test_vcs_operations
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17
17
18 Test suite for making push/pull operations.
18 Test suite for making push/pull operations.
19
19
20 Run it in two terminals::
20 Run it in two terminals::
21 paster serve kallithea/tests/test.ini
21 gearbox serve -c kallithea/tests/test.ini
22 KALLITHEA_WHOOSH_TEST_DISABLE=1 KALLITHEA_NO_TMP_PATH=1 py.test kallithea/tests/other/manual_test_vcs_operations.py
22 KALLITHEA_WHOOSH_TEST_DISABLE=1 KALLITHEA_NO_TMP_PATH=1 py.test kallithea/tests/other/manual_test_vcs_operations.py
23
23
24 You must have git > 1.8.1 for tests to work fine
24 You must have git > 1.8.1 for tests to work fine
25
25
26 This file was forked by the Kallithea project in July 2014.
26 This file was forked by the Kallithea project in July 2014.
27 Original author and date, and relevant copyright and licensing information is below:
27 Original author and date, and relevant copyright and licensing information is below:
28 :created_on: Dec 30, 2010
28 :created_on: Dec 30, 2010
29 :author: marcink
29 :author: marcink
30 :copyright: (c) 2013 RhodeCode GmbH, and others.
30 :copyright: (c) 2013 RhodeCode GmbH, and others.
31 :license: GPLv3, see LICENSE.md for more details.
31 :license: GPLv3, see LICENSE.md for more details.
32
32
33 """
33 """
34
34
35 import os
35 import os
36 import re
36 import re
37 import tempfile
37 import tempfile
38 import time
38 import time
39
39
40 from tempfile import _RandomNameSequence
40 from tempfile import _RandomNameSequence
41 from subprocess import Popen, PIPE
41 from subprocess import Popen, PIPE
42
42
43 from kallithea.tests.base import *
43 from kallithea.tests.base import *
44 from kallithea.tests.fixture import Fixture
44 from kallithea.tests.fixture import Fixture
45 from kallithea.model.db import User, Repository, UserIpMap, CacheInvalidation
45 from kallithea.model.db import User, Repository, UserIpMap, CacheInvalidation
46 from kallithea.model.meta import Session
46 from kallithea.model.meta import Session
47 from kallithea.model.repo import RepoModel
47 from kallithea.model.repo import RepoModel
48 from kallithea.model.user import UserModel
48 from kallithea.model.user import UserModel
49
49
50 DEBUG = True
50 DEBUG = True
51 HOST = '127.0.0.1:4999' # test host
51 HOST = '127.0.0.1:4999' # test host
52
52
53 fixture = Fixture()
53 fixture = Fixture()
54
54
55
55
56 class Command(object):
56 class Command(object):
57
57
58 def __init__(self, cwd):
58 def __init__(self, cwd):
59 self.cwd = cwd
59 self.cwd = cwd
60
60
61 def execute(self, cmd, *args, **environ):
61 def execute(self, cmd, *args, **environ):
62 """
62 """
63 Runs command on the system with given ``args``.
63 Runs command on the system with given ``args``.
64 """
64 """
65
65
66 command = cmd + ' ' + ' '.join(args)
66 command = cmd + ' ' + ' '.join(args)
67 if DEBUG:
67 if DEBUG:
68 print '*** CMD %s ***' % command
68 print '*** CMD %s ***' % command
69 testenv = dict(os.environ)
69 testenv = dict(os.environ)
70 testenv['LANG'] = 'en_US.UTF-8'
70 testenv['LANG'] = 'en_US.UTF-8'
71 testenv['LANGUAGE'] = 'en_US:en'
71 testenv['LANGUAGE'] = 'en_US:en'
72 testenv.update(environ)
72 testenv.update(environ)
73 p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE, cwd=self.cwd, env=testenv)
73 p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE, cwd=self.cwd, env=testenv)
74 stdout, stderr = p.communicate()
74 stdout, stderr = p.communicate()
75 if DEBUG:
75 if DEBUG:
76 if stdout:
76 if stdout:
77 print 'stdout:', repr(stdout)
77 print 'stdout:', repr(stdout)
78 if stderr:
78 if stderr:
79 print 'stderr:', repr(stderr)
79 print 'stderr:', repr(stderr)
80 return stdout, stderr
80 return stdout, stderr
81
81
82
82
83 def _get_tmp_dir():
83 def _get_tmp_dir():
84 return tempfile.mkdtemp(prefix='rc_integration_test')
84 return tempfile.mkdtemp(prefix='rc_integration_test')
85
85
86
86
87 def _construct_url(repo, dest=None, **kwargs):
87 def _construct_url(repo, dest=None, **kwargs):
88 if dest is None:
88 if dest is None:
89 #make temp clone
89 #make temp clone
90 dest = _get_tmp_dir()
90 dest = _get_tmp_dir()
91 params = {
91 params = {
92 'user': TEST_USER_ADMIN_LOGIN,
92 'user': TEST_USER_ADMIN_LOGIN,
93 'passwd': TEST_USER_ADMIN_PASS,
93 'passwd': TEST_USER_ADMIN_PASS,
94 'host': HOST,
94 'host': HOST,
95 'cloned_repo': repo,
95 'cloned_repo': repo,
96 'dest': dest
96 'dest': dest
97 }
97 }
98 params.update(**kwargs)
98 params.update(**kwargs)
99 if params['user'] and params['passwd']:
99 if params['user'] and params['passwd']:
100 _url = 'http://%(user)s:%(passwd)s@%(host)s/%(cloned_repo)s %(dest)s' % params
100 _url = 'http://%(user)s:%(passwd)s@%(host)s/%(cloned_repo)s %(dest)s' % params
101 else:
101 else:
102 _url = 'http://(host)s/%(cloned_repo)s %(dest)s' % params
102 _url = 'http://(host)s/%(cloned_repo)s %(dest)s' % params
103 return _url
103 return _url
104
104
105
105
106 def _add_files_and_push(vcs, DEST, **kwargs):
106 def _add_files_and_push(vcs, DEST, **kwargs):
107 """
107 """
108 Generate some files, add it to DEST repo and push back
108 Generate some files, add it to DEST repo and push back
109 vcs is git or hg and defines what VCS we want to make those files for
109 vcs is git or hg and defines what VCS we want to make those files for
110
110
111 :param vcs:
111 :param vcs:
112 :param DEST:
112 :param DEST:
113 """
113 """
114 # commit some stuff into this repo
114 # commit some stuff into this repo
115 cwd = path = os.path.join(DEST)
115 cwd = path = os.path.join(DEST)
116 #added_file = os.path.join(path, '%ssetupΔ…ΕΌΕΊΔ‡.py' % _RandomNameSequence().next())
116 #added_file = os.path.join(path, '%ssetupΔ…ΕΌΕΊΔ‡.py' % _RandomNameSequence().next())
117 added_file = os.path.join(path, '%ssetup.py' % _RandomNameSequence().next())
117 added_file = os.path.join(path, '%ssetup.py' % _RandomNameSequence().next())
118 Command(cwd).execute('touch %s' % added_file)
118 Command(cwd).execute('touch %s' % added_file)
119 Command(cwd).execute('%s add %s' % (vcs, added_file))
119 Command(cwd).execute('%s add %s' % (vcs, added_file))
120
120
121 email = 'me@example.com'
121 email = 'me@example.com'
122 if os.name == 'nt':
122 if os.name == 'nt':
123 author_str = 'User <%s>' % email
123 author_str = 'User <%s>' % email
124 else:
124 else:
125 author_str = 'User ǝɯɐᴎ <%s>' % email
125 author_str = 'User ǝɯɐᴎ <%s>' % email
126 for i in xrange(kwargs.get('files_no', 3)):
126 for i in xrange(kwargs.get('files_no', 3)):
127 cmd = """echo "added_line%s" >> %s""" % (i, added_file)
127 cmd = """echo "added_line%s" >> %s""" % (i, added_file)
128 Command(cwd).execute(cmd)
128 Command(cwd).execute(cmd)
129 if vcs == 'hg':
129 if vcs == 'hg':
130 cmd = """hg commit -m "committed new %s" -u "%s" "%s" """ % (
130 cmd = """hg commit -m "committed new %s" -u "%s" "%s" """ % (
131 i, author_str, added_file
131 i, author_str, added_file
132 )
132 )
133 elif vcs == 'git':
133 elif vcs == 'git':
134 cmd = """git commit -m "committed new %s" --author "%s" "%s" """ % (
134 cmd = """git commit -m "committed new %s" --author "%s" "%s" """ % (
135 i, author_str, added_file
135 i, author_str, added_file
136 )
136 )
137 # git commit needs EMAIL on some machines
137 # git commit needs EMAIL on some machines
138 Command(cwd).execute(cmd, EMAIL=email)
138 Command(cwd).execute(cmd, EMAIL=email)
139
139
140 # PUSH it back
140 # PUSH it back
141 _REPO = None
141 _REPO = None
142 if vcs == 'hg':
142 if vcs == 'hg':
143 _REPO = HG_REPO
143 _REPO = HG_REPO
144 elif vcs == 'git':
144 elif vcs == 'git':
145 _REPO = GIT_REPO
145 _REPO = GIT_REPO
146
146
147 kwargs['dest'] = ''
147 kwargs['dest'] = ''
148 clone_url = _construct_url(_REPO, **kwargs)
148 clone_url = _construct_url(_REPO, **kwargs)
149 if 'clone_url' in kwargs:
149 if 'clone_url' in kwargs:
150 clone_url = kwargs['clone_url']
150 clone_url = kwargs['clone_url']
151 stdout = stderr = None
151 stdout = stderr = None
152 if vcs == 'hg':
152 if vcs == 'hg':
153 stdout, stderr = Command(cwd).execute('hg push --verbose', clone_url)
153 stdout, stderr = Command(cwd).execute('hg push --verbose', clone_url)
154 elif vcs == 'git':
154 elif vcs == 'git':
155 stdout, stderr = Command(cwd).execute('git push --verbose', clone_url + " master")
155 stdout, stderr = Command(cwd).execute('git push --verbose', clone_url + " master")
156
156
157 return stdout, stderr
157 return stdout, stderr
158
158
159
159
160 def set_anonymous_access(enable=True):
160 def set_anonymous_access(enable=True):
161 user = User.get_default_user()
161 user = User.get_default_user()
162 user.active = enable
162 user.active = enable
163 Session().commit()
163 Session().commit()
164 print '\tanonymous access is now:', enable
164 print '\tanonymous access is now:', enable
165 if enable != User.get_default_user().active:
165 if enable != User.get_default_user().active:
166 raise Exception('Cannot set anonymous access')
166 raise Exception('Cannot set anonymous access')
167
167
168
168
169 #==============================================================================
169 #==============================================================================
170 # TESTS
170 # TESTS
171 #==============================================================================
171 #==============================================================================
172
172
173
173
174 def _check_proper_git_push(stdout, stderr):
174 def _check_proper_git_push(stdout, stderr):
175 #WTF Git stderr is output ?!
175 #WTF Git stderr is output ?!
176 assert 'fatal' not in stderr
176 assert 'fatal' not in stderr
177 assert 'rejected' not in stderr
177 assert 'rejected' not in stderr
178 assert 'Pushing to' in stderr
178 assert 'Pushing to' in stderr
179 assert 'master -> master' in stderr
179 assert 'master -> master' in stderr
180
180
181
181
182 class TestVCSOperations(TestController):
182 class TestVCSOperations(TestController):
183
183
184 @classmethod
184 @classmethod
185 def setup_class(cls):
185 def setup_class(cls):
186 #DISABLE ANONYMOUS ACCESS
186 #DISABLE ANONYMOUS ACCESS
187 set_anonymous_access(False)
187 set_anonymous_access(False)
188
188
189 def setup_method(self, method):
189 def setup_method(self, method):
190 r = Repository.get_by_repo_name(GIT_REPO)
190 r = Repository.get_by_repo_name(GIT_REPO)
191 Repository.unlock(r)
191 Repository.unlock(r)
192 r.enable_locking = False
192 r.enable_locking = False
193 Session().commit()
193 Session().commit()
194
194
195 r = Repository.get_by_repo_name(HG_REPO)
195 r = Repository.get_by_repo_name(HG_REPO)
196 Repository.unlock(r)
196 Repository.unlock(r)
197 r.enable_locking = False
197 r.enable_locking = False
198 Session().commit()
198 Session().commit()
199
199
200 def test_clone_hg_repo_by_admin(self):
200 def test_clone_hg_repo_by_admin(self):
201 clone_url = _construct_url(HG_REPO)
201 clone_url = _construct_url(HG_REPO)
202 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
202 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
203
203
204 assert 'requesting all changes' in stdout
204 assert 'requesting all changes' in stdout
205 assert 'adding changesets' in stdout
205 assert 'adding changesets' in stdout
206 assert 'adding manifests' in stdout
206 assert 'adding manifests' in stdout
207 assert 'adding file changes' in stdout
207 assert 'adding file changes' in stdout
208
208
209 assert stderr == ''
209 assert stderr == ''
210
210
211 def test_clone_git_repo_by_admin(self):
211 def test_clone_git_repo_by_admin(self):
212 clone_url = _construct_url(GIT_REPO)
212 clone_url = _construct_url(GIT_REPO)
213 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
213 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
214
214
215 assert 'Cloning into' in stdout + stderr
215 assert 'Cloning into' in stdout + stderr
216 assert stderr == '' or stdout == ''
216 assert stderr == '' or stdout == ''
217
217
218 def test_clone_wrong_credentials_hg(self):
218 def test_clone_wrong_credentials_hg(self):
219 clone_url = _construct_url(HG_REPO, passwd='bad!')
219 clone_url = _construct_url(HG_REPO, passwd='bad!')
220 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
220 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
221 assert 'abort: authorization failed' in stderr
221 assert 'abort: authorization failed' in stderr
222
222
223 def test_clone_wrong_credentials_git(self):
223 def test_clone_wrong_credentials_git(self):
224 clone_url = _construct_url(GIT_REPO, passwd='bad!')
224 clone_url = _construct_url(GIT_REPO, passwd='bad!')
225 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
225 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
226 assert 'fatal: Authentication failed' in stderr
226 assert 'fatal: Authentication failed' in stderr
227
227
228 def test_clone_git_dir_as_hg(self):
228 def test_clone_git_dir_as_hg(self):
229 clone_url = _construct_url(GIT_REPO)
229 clone_url = _construct_url(GIT_REPO)
230 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
230 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
231 assert 'HTTP Error 404: Not Found' in stderr
231 assert 'HTTP Error 404: Not Found' in stderr
232
232
233 def test_clone_hg_repo_as_git(self):
233 def test_clone_hg_repo_as_git(self):
234 clone_url = _construct_url(HG_REPO)
234 clone_url = _construct_url(HG_REPO)
235 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
235 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
236 assert 'not found' in stderr
236 assert 'not found' in stderr
237
237
238 def test_clone_non_existing_path_hg(self):
238 def test_clone_non_existing_path_hg(self):
239 clone_url = _construct_url('trololo')
239 clone_url = _construct_url('trololo')
240 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
240 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
241 assert 'HTTP Error 404: Not Found' in stderr
241 assert 'HTTP Error 404: Not Found' in stderr
242
242
243 def test_clone_non_existing_path_git(self):
243 def test_clone_non_existing_path_git(self):
244 clone_url = _construct_url('trololo')
244 clone_url = _construct_url('trololo')
245 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
245 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
246 assert 'not found' in stderr
246 assert 'not found' in stderr
247
247
248 def test_push_new_file_hg(self):
248 def test_push_new_file_hg(self):
249 DEST = _get_tmp_dir()
249 DEST = _get_tmp_dir()
250 clone_url = _construct_url(HG_REPO, dest=DEST)
250 clone_url = _construct_url(HG_REPO, dest=DEST)
251 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
251 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
252
252
253 fork_name = '%s_fork%s' % (HG_REPO, _RandomNameSequence().next())
253 fork_name = '%s_fork%s' % (HG_REPO, _RandomNameSequence().next())
254 fixture.create_fork(HG_REPO, fork_name)
254 fixture.create_fork(HG_REPO, fork_name)
255 clone_url = _construct_url(fork_name).split()[0]
255 clone_url = _construct_url(fork_name).split()[0]
256 stdout, stderr = _add_files_and_push('hg', DEST, clone_url=clone_url)
256 stdout, stderr = _add_files_and_push('hg', DEST, clone_url=clone_url)
257
257
258 assert 'pushing to' in stdout
258 assert 'pushing to' in stdout
259 assert 'Repository size' in stdout
259 assert 'Repository size' in stdout
260 assert 'Last revision is now' in stdout
260 assert 'Last revision is now' in stdout
261
261
262 def test_push_new_file_git(self):
262 def test_push_new_file_git(self):
263 DEST = _get_tmp_dir()
263 DEST = _get_tmp_dir()
264 clone_url = _construct_url(GIT_REPO, dest=DEST)
264 clone_url = _construct_url(GIT_REPO, dest=DEST)
265 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
265 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
266
266
267 # commit some stuff into this repo
267 # commit some stuff into this repo
268 fork_name = '%s_fork%s' % (GIT_REPO, _RandomNameSequence().next())
268 fork_name = '%s_fork%s' % (GIT_REPO, _RandomNameSequence().next())
269 fixture.create_fork(GIT_REPO, fork_name)
269 fixture.create_fork(GIT_REPO, fork_name)
270 clone_url = _construct_url(fork_name).split()[0]
270 clone_url = _construct_url(fork_name).split()[0]
271 stdout, stderr = _add_files_and_push('git', DEST, clone_url=clone_url)
271 stdout, stderr = _add_files_and_push('git', DEST, clone_url=clone_url)
272 print [(x.repo_full_path,x.repo_path) for x in Repository.query()] # TODO: what is this for
272 print [(x.repo_full_path,x.repo_path) for x in Repository.query()] # TODO: what is this for
273 _check_proper_git_push(stdout, stderr)
273 _check_proper_git_push(stdout, stderr)
274
274
275 def test_push_invalidates_cache_hg(self):
275 def test_push_invalidates_cache_hg(self):
276 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
276 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
277 ==HG_REPO).scalar()
277 ==HG_REPO).scalar()
278 if not key:
278 if not key:
279 key = CacheInvalidation(HG_REPO, HG_REPO)
279 key = CacheInvalidation(HG_REPO, HG_REPO)
280 Session().add(key)
280 Session().add(key)
281
281
282 key.cache_active = True
282 key.cache_active = True
283 Session().commit()
283 Session().commit()
284
284
285 DEST = _get_tmp_dir()
285 DEST = _get_tmp_dir()
286 clone_url = _construct_url(HG_REPO, dest=DEST)
286 clone_url = _construct_url(HG_REPO, dest=DEST)
287 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
287 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
288
288
289 fork_name = '%s_fork%s' % (HG_REPO, _RandomNameSequence().next())
289 fork_name = '%s_fork%s' % (HG_REPO, _RandomNameSequence().next())
290 fixture.create_fork(HG_REPO, fork_name)
290 fixture.create_fork(HG_REPO, fork_name)
291 clone_url = _construct_url(fork_name).split()[0]
291 clone_url = _construct_url(fork_name).split()[0]
292 stdout, stderr = _add_files_and_push('hg', DEST, files_no=1, clone_url=clone_url)
292 stdout, stderr = _add_files_and_push('hg', DEST, files_no=1, clone_url=clone_url)
293
293
294 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
294 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
295 ==fork_name).all()
295 ==fork_name).all()
296 assert key == []
296 assert key == []
297
297
298 def test_push_invalidates_cache_git(self):
298 def test_push_invalidates_cache_git(self):
299 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
299 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
300 ==GIT_REPO).scalar()
300 ==GIT_REPO).scalar()
301 if not key:
301 if not key:
302 key = CacheInvalidation(GIT_REPO, GIT_REPO)
302 key = CacheInvalidation(GIT_REPO, GIT_REPO)
303 Session().add(key)
303 Session().add(key)
304
304
305 key.cache_active = True
305 key.cache_active = True
306 Session().commit()
306 Session().commit()
307
307
308 DEST = _get_tmp_dir()
308 DEST = _get_tmp_dir()
309 clone_url = _construct_url(GIT_REPO, dest=DEST)
309 clone_url = _construct_url(GIT_REPO, dest=DEST)
310 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
310 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
311
311
312 # commit some stuff into this repo
312 # commit some stuff into this repo
313 fork_name = '%s_fork%s' % (GIT_REPO, _RandomNameSequence().next())
313 fork_name = '%s_fork%s' % (GIT_REPO, _RandomNameSequence().next())
314 fixture.create_fork(GIT_REPO, fork_name)
314 fixture.create_fork(GIT_REPO, fork_name)
315 clone_url = _construct_url(fork_name).split()[0]
315 clone_url = _construct_url(fork_name).split()[0]
316 stdout, stderr = _add_files_and_push('git', DEST, files_no=1, clone_url=clone_url)
316 stdout, stderr = _add_files_and_push('git', DEST, files_no=1, clone_url=clone_url)
317 _check_proper_git_push(stdout, stderr)
317 _check_proper_git_push(stdout, stderr)
318
318
319 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
319 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
320 ==fork_name).all()
320 ==fork_name).all()
321 assert key == []
321 assert key == []
322
322
323 def test_push_wrong_credentials_hg(self):
323 def test_push_wrong_credentials_hg(self):
324 DEST = _get_tmp_dir()
324 DEST = _get_tmp_dir()
325 clone_url = _construct_url(HG_REPO, dest=DEST)
325 clone_url = _construct_url(HG_REPO, dest=DEST)
326 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
326 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
327
327
328 stdout, stderr = _add_files_and_push('hg', DEST, user='bad',
328 stdout, stderr = _add_files_and_push('hg', DEST, user='bad',
329 passwd='name')
329 passwd='name')
330
330
331 assert 'abort: authorization failed' in stderr
331 assert 'abort: authorization failed' in stderr
332
332
333 def test_push_wrong_credentials_git(self):
333 def test_push_wrong_credentials_git(self):
334 DEST = _get_tmp_dir()
334 DEST = _get_tmp_dir()
335 clone_url = _construct_url(GIT_REPO, dest=DEST)
335 clone_url = _construct_url(GIT_REPO, dest=DEST)
336 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
336 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
337
337
338 stdout, stderr = _add_files_and_push('git', DEST, user='bad',
338 stdout, stderr = _add_files_and_push('git', DEST, user='bad',
339 passwd='name')
339 passwd='name')
340
340
341 assert 'fatal: Authentication failed' in stderr
341 assert 'fatal: Authentication failed' in stderr
342
342
343 def test_push_back_to_wrong_url_hg(self):
343 def test_push_back_to_wrong_url_hg(self):
344 DEST = _get_tmp_dir()
344 DEST = _get_tmp_dir()
345 clone_url = _construct_url(HG_REPO, dest=DEST)
345 clone_url = _construct_url(HG_REPO, dest=DEST)
346 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
346 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
347
347
348 stdout, stderr = _add_files_and_push('hg', DEST,
348 stdout, stderr = _add_files_and_push('hg', DEST,
349 clone_url='http://%s/tmp' % HOST)
349 clone_url='http://%s/tmp' % HOST)
350
350
351 assert 'HTTP Error 404: Not Found' in stderr
351 assert 'HTTP Error 404: Not Found' in stderr
352
352
353 def test_push_back_to_wrong_url_git(self):
353 def test_push_back_to_wrong_url_git(self):
354 DEST = _get_tmp_dir()
354 DEST = _get_tmp_dir()
355 clone_url = _construct_url(GIT_REPO, dest=DEST)
355 clone_url = _construct_url(GIT_REPO, dest=DEST)
356 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
356 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
357
357
358 stdout, stderr = _add_files_and_push('git', DEST,
358 stdout, stderr = _add_files_and_push('git', DEST,
359 clone_url='http://%s/tmp' % HOST)
359 clone_url='http://%s/tmp' % HOST)
360
360
361 assert 'not found' in stderr
361 assert 'not found' in stderr
362
362
363 def test_clone_and_create_lock_hg(self):
363 def test_clone_and_create_lock_hg(self):
364 # enable locking
364 # enable locking
365 r = Repository.get_by_repo_name(HG_REPO)
365 r = Repository.get_by_repo_name(HG_REPO)
366 r.enable_locking = True
366 r.enable_locking = True
367 Session().commit()
367 Session().commit()
368 # clone
368 # clone
369 clone_url = _construct_url(HG_REPO)
369 clone_url = _construct_url(HG_REPO)
370 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
370 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
371
371
372 #check if lock was made
372 #check if lock was made
373 r = Repository.get_by_repo_name(HG_REPO)
373 r = Repository.get_by_repo_name(HG_REPO)
374 assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
374 assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
375
375
376 def test_clone_and_create_lock_git(self):
376 def test_clone_and_create_lock_git(self):
377 # enable locking
377 # enable locking
378 r = Repository.get_by_repo_name(GIT_REPO)
378 r = Repository.get_by_repo_name(GIT_REPO)
379 r.enable_locking = True
379 r.enable_locking = True
380 Session().commit()
380 Session().commit()
381 # clone
381 # clone
382 clone_url = _construct_url(GIT_REPO)
382 clone_url = _construct_url(GIT_REPO)
383 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
383 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
384
384
385 #check if lock was made
385 #check if lock was made
386 r = Repository.get_by_repo_name(GIT_REPO)
386 r = Repository.get_by_repo_name(GIT_REPO)
387 assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
387 assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
388
388
389 def test_clone_after_repo_was_locked_hg(self):
389 def test_clone_after_repo_was_locked_hg(self):
390 #lock repo
390 #lock repo
391 r = Repository.get_by_repo_name(HG_REPO)
391 r = Repository.get_by_repo_name(HG_REPO)
392 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
392 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
393 #pull fails since repo is locked
393 #pull fails since repo is locked
394 clone_url = _construct_url(HG_REPO)
394 clone_url = _construct_url(HG_REPO)
395 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
395 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
396 msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
396 msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
397 % (HG_REPO, TEST_USER_ADMIN_LOGIN))
397 % (HG_REPO, TEST_USER_ADMIN_LOGIN))
398 assert msg in stderr
398 assert msg in stderr
399
399
400 def test_clone_after_repo_was_locked_git(self):
400 def test_clone_after_repo_was_locked_git(self):
401 #lock repo
401 #lock repo
402 r = Repository.get_by_repo_name(GIT_REPO)
402 r = Repository.get_by_repo_name(GIT_REPO)
403 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
403 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
404 #pull fails since repo is locked
404 #pull fails since repo is locked
405 clone_url = _construct_url(GIT_REPO)
405 clone_url = _construct_url(GIT_REPO)
406 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
406 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
407 msg = ("""The requested URL returned error: 423""")
407 msg = ("""The requested URL returned error: 423""")
408 assert msg in stderr
408 assert msg in stderr
409
409
410 def test_push_on_locked_repo_by_other_user_hg(self):
410 def test_push_on_locked_repo_by_other_user_hg(self):
411 #clone some temp
411 #clone some temp
412 DEST = _get_tmp_dir()
412 DEST = _get_tmp_dir()
413 clone_url = _construct_url(HG_REPO, dest=DEST)
413 clone_url = _construct_url(HG_REPO, dest=DEST)
414 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
414 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
415
415
416 #lock repo
416 #lock repo
417 r = Repository.get_by_repo_name(HG_REPO)
417 r = Repository.get_by_repo_name(HG_REPO)
418 # let this user actually push !
418 # let this user actually push !
419 RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
419 RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
420 perm='repository.write')
420 perm='repository.write')
421 Session().commit()
421 Session().commit()
422 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
422 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
423
423
424 #push fails repo is locked by other user !
424 #push fails repo is locked by other user !
425 stdout, stderr = _add_files_and_push('hg', DEST,
425 stdout, stderr = _add_files_and_push('hg', DEST,
426 user=TEST_USER_REGULAR_LOGIN,
426 user=TEST_USER_REGULAR_LOGIN,
427 passwd=TEST_USER_REGULAR_PASS)
427 passwd=TEST_USER_REGULAR_PASS)
428 msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
428 msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
429 % (HG_REPO, TEST_USER_ADMIN_LOGIN))
429 % (HG_REPO, TEST_USER_ADMIN_LOGIN))
430 assert msg in stderr
430 assert msg in stderr
431
431
432 def test_push_on_locked_repo_by_other_user_git(self):
432 def test_push_on_locked_repo_by_other_user_git(self):
433 #clone some temp
433 #clone some temp
434 DEST = _get_tmp_dir()
434 DEST = _get_tmp_dir()
435 clone_url = _construct_url(GIT_REPO, dest=DEST)
435 clone_url = _construct_url(GIT_REPO, dest=DEST)
436 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
436 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
437
437
438 #lock repo
438 #lock repo
439 r = Repository.get_by_repo_name(GIT_REPO)
439 r = Repository.get_by_repo_name(GIT_REPO)
440 # let this user actually push !
440 # let this user actually push !
441 RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
441 RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
442 perm='repository.write')
442 perm='repository.write')
443 Session().commit()
443 Session().commit()
444 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
444 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
445
445
446 #push fails repo is locked by other user !
446 #push fails repo is locked by other user !
447 stdout, stderr = _add_files_and_push('git', DEST,
447 stdout, stderr = _add_files_and_push('git', DEST,
448 user=TEST_USER_REGULAR_LOGIN,
448 user=TEST_USER_REGULAR_LOGIN,
449 passwd=TEST_USER_REGULAR_PASS)
449 passwd=TEST_USER_REGULAR_PASS)
450 err = 'Repository `%s` locked by user `%s`' % (GIT_REPO, TEST_USER_ADMIN_LOGIN)
450 err = 'Repository `%s` locked by user `%s`' % (GIT_REPO, TEST_USER_ADMIN_LOGIN)
451 assert err in stderr
451 assert err in stderr
452
452
453 #TODO: fix this somehow later on Git, Git is stupid and even if we throw
453 #TODO: fix this somehow later on Git, Git is stupid and even if we throw
454 #back 423 to it, it makes ANOTHER request and we fail there with 405 :/
454 #back 423 to it, it makes ANOTHER request and we fail there with 405 :/
455
455
456 msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
456 msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
457 % (GIT_REPO, TEST_USER_ADMIN_LOGIN))
457 % (GIT_REPO, TEST_USER_ADMIN_LOGIN))
458 #msg = "405 Method Not Allowed"
458 #msg = "405 Method Not Allowed"
459 #assert msg in stderr
459 #assert msg in stderr
460
460
461 def test_push_unlocks_repository_hg(self):
461 def test_push_unlocks_repository_hg(self):
462 # enable locking
462 # enable locking
463 fork_name = '%s_fork%s' % (HG_REPO, _RandomNameSequence().next())
463 fork_name = '%s_fork%s' % (HG_REPO, _RandomNameSequence().next())
464 fixture.create_fork(HG_REPO, fork_name)
464 fixture.create_fork(HG_REPO, fork_name)
465 r = Repository.get_by_repo_name(fork_name)
465 r = Repository.get_by_repo_name(fork_name)
466 r.enable_locking = True
466 r.enable_locking = True
467 Session().commit()
467 Session().commit()
468 #clone some temp
468 #clone some temp
469 DEST = _get_tmp_dir()
469 DEST = _get_tmp_dir()
470 clone_url = _construct_url(fork_name, dest=DEST)
470 clone_url = _construct_url(fork_name, dest=DEST)
471 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
471 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
472
472
473 #check for lock repo after clone
473 #check for lock repo after clone
474 r = Repository.get_by_repo_name(fork_name)
474 r = Repository.get_by_repo_name(fork_name)
475 uid = User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
475 uid = User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
476 assert r.locked[0] == uid
476 assert r.locked[0] == uid
477
477
478 #push is ok and repo is now unlocked
478 #push is ok and repo is now unlocked
479 stdout, stderr = _add_files_and_push('hg', DEST, clone_url=clone_url.split()[0])
479 stdout, stderr = _add_files_and_push('hg', DEST, clone_url=clone_url.split()[0])
480 assert str('remote: Released lock on repo `%s`' % fork_name) in stdout
480 assert str('remote: Released lock on repo `%s`' % fork_name) in stdout
481 #we need to cleanup the Session Here !
481 #we need to cleanup the Session Here !
482 Session.remove()
482 Session.remove()
483 r = Repository.get_by_repo_name(fork_name)
483 r = Repository.get_by_repo_name(fork_name)
484 assert r.locked == [None, None]
484 assert r.locked == [None, None]
485
485
486 #TODO: fix me ! somehow during tests hooks don't get called on Git
486 #TODO: fix me ! somehow during tests hooks don't get called on Git
487 def test_push_unlocks_repository_git(self):
487 def test_push_unlocks_repository_git(self):
488 # enable locking
488 # enable locking
489 fork_name = '%s_fork%s' % (GIT_REPO, _RandomNameSequence().next())
489 fork_name = '%s_fork%s' % (GIT_REPO, _RandomNameSequence().next())
490 fixture.create_fork(GIT_REPO, fork_name)
490 fixture.create_fork(GIT_REPO, fork_name)
491 r = Repository.get_by_repo_name(fork_name)
491 r = Repository.get_by_repo_name(fork_name)
492 r.enable_locking = True
492 r.enable_locking = True
493 Session().commit()
493 Session().commit()
494 #clone some temp
494 #clone some temp
495 DEST = _get_tmp_dir()
495 DEST = _get_tmp_dir()
496 clone_url = _construct_url(fork_name, dest=DEST)
496 clone_url = _construct_url(fork_name, dest=DEST)
497 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
497 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
498
498
499 #check for lock repo after clone
499 #check for lock repo after clone
500 r = Repository.get_by_repo_name(fork_name)
500 r = Repository.get_by_repo_name(fork_name)
501 assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
501 assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
502
502
503 #push is ok and repo is now unlocked
503 #push is ok and repo is now unlocked
504 stdout, stderr = _add_files_and_push('git', DEST, clone_url=clone_url.split()[0])
504 stdout, stderr = _add_files_and_push('git', DEST, clone_url=clone_url.split()[0])
505 _check_proper_git_push(stdout, stderr)
505 _check_proper_git_push(stdout, stderr)
506
506
507 assert ('remote: Released lock on repo `%s`' % fork_name) in stderr
507 assert ('remote: Released lock on repo `%s`' % fork_name) in stderr
508 #we need to cleanup the Session Here !
508 #we need to cleanup the Session Here !
509 Session.remove()
509 Session.remove()
510 r = Repository.get_by_repo_name(fork_name)
510 r = Repository.get_by_repo_name(fork_name)
511 assert r.locked == [None, None]
511 assert r.locked == [None, None]
512
512
513 def test_ip_restriction_hg(self):
513 def test_ip_restriction_hg(self):
514 user_model = UserModel()
514 user_model = UserModel()
515 try:
515 try:
516 user_model.add_extra_ip(TEST_USER_ADMIN_LOGIN, '10.10.10.10/32')
516 user_model.add_extra_ip(TEST_USER_ADMIN_LOGIN, '10.10.10.10/32')
517 Session().commit()
517 Session().commit()
518 clone_url = _construct_url(HG_REPO)
518 clone_url = _construct_url(HG_REPO)
519 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
519 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
520 assert 'abort: HTTP Error 403: Forbidden' in stderr
520 assert 'abort: HTTP Error 403: Forbidden' in stderr
521 finally:
521 finally:
522 #release IP restrictions
522 #release IP restrictions
523 for ip in UserIpMap.query():
523 for ip in UserIpMap.query():
524 UserIpMap.delete(ip.ip_id)
524 UserIpMap.delete(ip.ip_id)
525 Session().commit()
525 Session().commit()
526
526
527 # IP permissions are cached, need to invalidate this cache explicitly
527 # IP permissions are cached, need to invalidate this cache explicitly
528 invalidate_all_caches()
528 invalidate_all_caches()
529
529
530 clone_url = _construct_url(HG_REPO)
530 clone_url = _construct_url(HG_REPO)
531 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
531 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
532
532
533 assert 'requesting all changes' in stdout
533 assert 'requesting all changes' in stdout
534 assert 'adding changesets' in stdout
534 assert 'adding changesets' in stdout
535 assert 'adding manifests' in stdout
535 assert 'adding manifests' in stdout
536 assert 'adding file changes' in stdout
536 assert 'adding file changes' in stdout
537
537
538 assert stderr == ''
538 assert stderr == ''
539
539
540 def test_ip_restriction_git(self):
540 def test_ip_restriction_git(self):
541 user_model = UserModel()
541 user_model = UserModel()
542 try:
542 try:
543 user_model.add_extra_ip(TEST_USER_ADMIN_LOGIN, '10.10.10.10/32')
543 user_model.add_extra_ip(TEST_USER_ADMIN_LOGIN, '10.10.10.10/32')
544 Session().commit()
544 Session().commit()
545 clone_url = _construct_url(GIT_REPO)
545 clone_url = _construct_url(GIT_REPO)
546 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
546 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
547 # The message apparently changed in Git 1.8.3, so match it loosely.
547 # The message apparently changed in Git 1.8.3, so match it loosely.
548 assert re.search(r'\b403\b', stderr)
548 assert re.search(r'\b403\b', stderr)
549 finally:
549 finally:
550 #release IP restrictions
550 #release IP restrictions
551 for ip in UserIpMap.query():
551 for ip in UserIpMap.query():
552 UserIpMap.delete(ip.ip_id)
552 UserIpMap.delete(ip.ip_id)
553 Session().commit()
553 Session().commit()
554
554
555 # IP permissions are cached, need to invalidate this cache explicitly
555 # IP permissions are cached, need to invalidate this cache explicitly
556 invalidate_all_caches()
556 invalidate_all_caches()
557
557
558 clone_url = _construct_url(GIT_REPO)
558 clone_url = _construct_url(GIT_REPO)
559 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
559 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
560
560
561 assert 'Cloning into' in stdout + stderr
561 assert 'Cloning into' in stdout + stderr
562 assert stderr == '' or stdout == ''
562 assert stderr == '' or stdout == ''
@@ -1,17 +1,17 b''
1 #!/bin/sh
1 #!/bin/sh
2 psql -U postgres -h localhost -c 'drop database if exists kallithea;'
2 psql -U postgres -h localhost -c 'drop database if exists kallithea;'
3 psql -U postgres -h localhost -c 'create database kallithea;'
3 psql -U postgres -h localhost -c 'create database kallithea;'
4 paster setup-db server.ini --force-yes --user=username --password=qweqwe --email=username@example.com --repos=/home/username/repos --no-public-access
4 gearbox setup-db -c server.ini --force-yes --user=username --password=qweqwe --email=username@example.com --repos=/home/username/repos --no-public-access
5 API_KEY=`psql -R " " -A -U postgres -h localhost -c "select api_key from users where admin=TRUE" -d kallithea | awk '{print $2}'`
5 API_KEY=`psql -R " " -A -U postgres -h localhost -c "select api_key from users where admin=TRUE" -d kallithea | awk '{print $2}'`
6 echo "run those after running server"
6 echo "run those after running server"
7 paster serve server.ini --pid-file=server.pid --daemon
7 gearbox serve -c server.ini --pid-file=server.pid --daemon
8 sleep 3
8 sleep 3
9 kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo1 password:qweqwe email:demo1@example.com
9 kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo1 password:qweqwe email:demo1@example.com
10 kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo2 password:qweqwe email:demo2@example.com
10 kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo2 password:qweqwe email:demo2@example.com
11 kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo3 password:qweqwe email:demo3@example.com
11 kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo3 password:qweqwe email:demo3@example.com
12 kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user_group group_name:demo12
12 kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user_group group_name:demo12
13 kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 add_user_to_user_group usergroupid:demo12 userid:demo1
13 kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 add_user_to_user_group usergroupid:demo12 userid:demo1
14 kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 add_user_to_user_group usergroupid:demo12 userid:demo2
14 kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 add_user_to_user_group usergroupid:demo12 userid:demo2
15 echo "killing server"
15 echo "killing server"
16 kill `cat server.pid`
16 kill `cat server.pid`
17 rm server.pid
17 rm server.pid
@@ -1,605 +1,614 b''
1 ################################################################################
1 ################################################################################
2 ################################################################################
2 ################################################################################
3 # Kallithea - config for tests: #
3 # Kallithea - config for tests: #
4 # initial_repo_scan = true #
4 # initial_repo_scan = true #
5 # sqlalchemy and kallithea_test.sqlite #
5 # sqlalchemy and kallithea_test.sqlite #
6 # custom logging #
6 # custom logging #
7 # #
7 # #
8 # The %(here)s variable will be replaced with the parent directory of this file#
8 # The %(here)s variable will be replaced with the parent directory of this file#
9 ################################################################################
9 ################################################################################
10 ################################################################################
10 ################################################################################
11
11
12 [DEFAULT]
12 [DEFAULT]
13 debug = true
13 debug = true
14 pdebug = false
14 pdebug = false
15
15
16 ################################################################################
16 ################################################################################
17 ## Email settings ##
17 ## Email settings ##
18 ## ##
18 ## ##
19 ## Refer to the documentation ("Email settings") for more details. ##
19 ## Refer to the documentation ("Email settings") for more details. ##
20 ## ##
20 ## ##
21 ## It is recommended to use a valid sender address that passes access ##
21 ## It is recommended to use a valid sender address that passes access ##
22 ## validation and spam filtering in mail servers. ##
22 ## validation and spam filtering in mail servers. ##
23 ################################################################################
23 ################################################################################
24
24
25 ## 'From' header for application emails. You can optionally add a name.
25 ## 'From' header for application emails. You can optionally add a name.
26 ## Default:
26 ## Default:
27 #app_email_from = Kallithea
27 #app_email_from = Kallithea
28 ## Examples:
28 ## Examples:
29 #app_email_from = Kallithea <kallithea-noreply@example.com>
29 #app_email_from = Kallithea <kallithea-noreply@example.com>
30 #app_email_from = kallithea-noreply@example.com
30 #app_email_from = kallithea-noreply@example.com
31
31
32 ## Subject prefix for application emails.
32 ## Subject prefix for application emails.
33 ## A space between this prefix and the real subject is automatically added.
33 ## A space between this prefix and the real subject is automatically added.
34 ## Default:
34 ## Default:
35 #email_prefix =
35 #email_prefix =
36 ## Example:
36 ## Example:
37 #email_prefix = [Kallithea]
37 #email_prefix = [Kallithea]
38
38
39 ## Recipients for error emails and fallback recipients of application mails.
39 ## Recipients for error emails and fallback recipients of application mails.
40 ## Multiple addresses can be specified, space-separated.
40 ## Multiple addresses can be specified, space-separated.
41 ## Only addresses are allowed, do not add any name part.
41 ## Only addresses are allowed, do not add any name part.
42 ## Default:
42 ## Default:
43 #email_to =
43 #email_to =
44 ## Examples:
44 ## Examples:
45 #email_to = admin@example.com
45 #email_to = admin@example.com
46 #email_to = admin@example.com another_admin@example.com
46 #email_to = admin@example.com another_admin@example.com
47
47
48 ## 'From' header for error emails. You can optionally add a name.
48 ## 'From' header for error emails. You can optionally add a name.
49 ## Default:
49 ## Default:
50 #error_email_from = pylons@yourapp.com
50 #error_email_from = pylons@yourapp.com
51 ## Examples:
51 ## Examples:
52 #error_email_from = Kallithea Errors <kallithea-noreply@example.com>
52 #error_email_from = Kallithea Errors <kallithea-noreply@example.com>
53 #error_email_from = paste_error@example.com
53 #error_email_from = paste_error@example.com
54
54
55 ## SMTP server settings
55 ## SMTP server settings
56 ## If specifying credentials, make sure to use secure connections.
56 ## If specifying credentials, make sure to use secure connections.
57 ## Default: Send unencrypted unauthenticated mails to the specified smtp_server.
57 ## Default: Send unencrypted unauthenticated mails to the specified smtp_server.
58 ## For "SSL", use smtp_use_ssl = true and smtp_port = 465.
58 ## For "SSL", use smtp_use_ssl = true and smtp_port = 465.
59 ## For "STARTTLS", use smtp_use_tls = true and smtp_port = 587.
59 ## For "STARTTLS", use smtp_use_tls = true and smtp_port = 587.
60 #smtp_server = smtp.example.com
60 #smtp_server = smtp.example.com
61 #smtp_username =
61 #smtp_username =
62 #smtp_password =
62 #smtp_password =
63 #smtp_port = 25
63 #smtp_port = 25
64 #smtp_use_ssl = false
64 #smtp_use_ssl = false
65 #smtp_use_tls = false
65 #smtp_use_tls = false
66
66
67 [server:main]
67 [server:main]
68 ## PASTE ##
68 ## Gearbox default web server ##
69 #use = egg:Paste#http
69 #use = egg:gearbox#wsgiref
70 ## nr of worker threads to spawn
70 ## nr of worker threads to spawn
71 #threadpool_workers = 1
71 #threadpool_workers = 1
72 ## max request before thread respawn
72 ## max request before thread respawn
73 #threadpool_max_requests = 100
73 #threadpool_max_requests = 100
74 ## option to use threads of process
74 ## option to use threads of process
75 #use_threadpool = true
75 #use_threadpool = true
76
76
77 ## Gearbox gevent web server ##
78 #use = egg:gearbox#gevent
79
77 ## WAITRESS ##
80 ## WAITRESS ##
78 use = egg:waitress#main
81 use = egg:waitress#main
79 ## number of worker threads
82 ## number of worker threads
80 threads = 1
83 threads = 1
81 ## MAX BODY SIZE 100GB
84 ## MAX BODY SIZE 100GB
82 max_request_body_size = 107374182400
85 max_request_body_size = 107374182400
83 ## use poll instead of select, fixes fd limits, may not work on old
86 ## use poll instead of select, fixes fd limits, may not work on old
84 ## windows systems.
87 ## windows systems.
85 #asyncore_use_poll = True
88 #asyncore_use_poll = True
86
89
87 ## GUNICORN ##
90 ## GUNICORN ##
88 #use = egg:gunicorn#main
91 #use = egg:gunicorn#main
89 ## number of process workers. You must set `instance_id = *` when this option
92 ## number of process workers. You must set `instance_id = *` when this option
90 ## is set to more than one worker
93 ## is set to more than one worker
91 #workers = 1
94 #workers = 1
92 ## process name
95 ## process name
93 #proc_name = kallithea
96 #proc_name = kallithea
94 ## type of worker class, one of sync, eventlet, gevent, tornado
97 ## type of worker class, one of sync, eventlet, gevent, tornado
95 ## recommended for bigger setup is using of of other than sync one
98 ## recommended for bigger setup is using of of other than sync one
96 #worker_class = sync
99 #worker_class = sync
97 #max_requests = 1000
100 #max_requests = 1000
98 ## amount of time a worker can handle request before it gets killed and
101 ## amount of time a worker can handle request before it gets killed and
99 ## restarted
102 ## restarted
100 #timeout = 3600
103 #timeout = 3600
101
104
102 ## UWSGI ##
105 ## UWSGI ##
103 ## run with uwsgi --ini-paste-logged <inifile.ini>
106 ## run with uwsgi --ini-paste-logged <inifile.ini>
104 #[uwsgi]
107 #[uwsgi]
105 #socket = /tmp/uwsgi.sock
108 #socket = /tmp/uwsgi.sock
106 #master = true
109 #master = true
107 #http = 127.0.0.1:5000
110 #http = 127.0.0.1:5000
108
111
109 ## set as deamon and redirect all output to file
112 ## set as deamon and redirect all output to file
110 #daemonize = ./uwsgi_kallithea.log
113 #daemonize = ./uwsgi_kallithea.log
111
114
112 ## master process PID
115 ## master process PID
113 #pidfile = ./uwsgi_kallithea.pid
116 #pidfile = ./uwsgi_kallithea.pid
114
117
115 ## stats server with workers statistics, use uwsgitop
118 ## stats server with workers statistics, use uwsgitop
116 ## for monitoring, `uwsgitop 127.0.0.1:1717`
119 ## for monitoring, `uwsgitop 127.0.0.1:1717`
117 #stats = 127.0.0.1:1717
120 #stats = 127.0.0.1:1717
118 #memory-report = true
121 #memory-report = true
119
122
120 ## log 5XX errors
123 ## log 5XX errors
121 #log-5xx = true
124 #log-5xx = true
122
125
123 ## Set the socket listen queue size.
126 ## Set the socket listen queue size.
124 #listen = 256
127 #listen = 256
125
128
126 ## Gracefully Reload workers after the specified amount of managed requests
129 ## Gracefully Reload workers after the specified amount of managed requests
127 ## (avoid memory leaks).
130 ## (avoid memory leaks).
128 #max-requests = 1000
131 #max-requests = 1000
129
132
130 ## enable large buffers
133 ## enable large buffers
131 #buffer-size = 65535
134 #buffer-size = 65535
132
135
133 ## socket and http timeouts ##
136 ## socket and http timeouts ##
134 #http-timeout = 3600
137 #http-timeout = 3600
135 #socket-timeout = 3600
138 #socket-timeout = 3600
136
139
137 ## Log requests slower than the specified number of milliseconds.
140 ## Log requests slower than the specified number of milliseconds.
138 #log-slow = 10
141 #log-slow = 10
139
142
140 ## Exit if no app can be loaded.
143 ## Exit if no app can be loaded.
141 #need-app = true
144 #need-app = true
142
145
143 ## Set lazy mode (load apps in workers instead of master).
146 ## Set lazy mode (load apps in workers instead of master).
144 #lazy = true
147 #lazy = true
145
148
146 ## scaling ##
149 ## scaling ##
147 ## set cheaper algorithm to use, if not set default will be used
150 ## set cheaper algorithm to use, if not set default will be used
148 #cheaper-algo = spare
151 #cheaper-algo = spare
149
152
150 ## minimum number of workers to keep at all times
153 ## minimum number of workers to keep at all times
151 #cheaper = 1
154 #cheaper = 1
152
155
153 ## number of workers to spawn at startup
156 ## number of workers to spawn at startup
154 #cheaper-initial = 1
157 #cheaper-initial = 1
155
158
156 ## maximum number of workers that can be spawned
159 ## maximum number of workers that can be spawned
157 #workers = 4
160 #workers = 4
158
161
159 ## how many workers should be spawned at a time
162 ## how many workers should be spawned at a time
160 #cheaper-step = 1
163 #cheaper-step = 1
161
164
162 ## COMMON ##
165 ## COMMON ##
163 host = 127.0.0.1
166 host = 127.0.0.1
164 #port = 5000
167 #port = 5000
165 port = 4999
168 port = 4999
166
169
167 ## middleware for hosting the WSGI application under a URL prefix
170 ## middleware for hosting the WSGI application under a URL prefix
168 #[filter:proxy-prefix]
171 #[filter:proxy-prefix]
169 #use = egg:PasteDeploy#prefix
172 #use = egg:PasteDeploy#prefix
170 #prefix = /<your-prefix>
173 #prefix = /<your-prefix>
171
174
172 [app:main]
175 [app:main]
173 use = egg:kallithea
176 use = egg:kallithea
174 ## enable proxy prefix middleware
177 ## enable proxy prefix middleware
175 #filter-with = proxy-prefix
178 #filter-with = proxy-prefix
176
179
177 full_stack = true
180 full_stack = true
178 static_files = true
181 static_files = true
179 ## Available Languages:
182 ## Available Languages:
180 ## cs de fr hu ja nl_BE pl pt_BR ru sk zh_CN zh_TW
183 ## cs de fr hu ja nl_BE pl pt_BR ru sk zh_CN zh_TW
181 lang =
184 lang =
182 #cache_dir = %(here)s/data
185 #cache_dir = %(here)s/data
183 cache_dir = %(here)s/../../data/test/cache
186 cache_dir = %(here)s/../../data/test/cache
184 #index_dir = %(here)s/data/index
187 #index_dir = %(here)s/data/index
185 index_dir = %(here)s/../../data/test/index
188 index_dir = %(here)s/../../data/test/index
186
189
187 ## perform a full repository scan on each server start, this should be
190 ## perform a full repository scan on each server start, this should be
188 ## set to false after first startup, to allow faster server restarts.
191 ## set to false after first startup, to allow faster server restarts.
189 #initial_repo_scan = false
192 #initial_repo_scan = false
190 initial_repo_scan = true
193 initial_repo_scan = true
191
194
192 ## uncomment and set this path to use archive download cache
195 ## uncomment and set this path to use archive download cache
193 #archive_cache_dir = %(here)s/tarballcache
196 #archive_cache_dir = %(here)s/tarballcache
194 archive_cache_dir = %(here)s/../../data/test/tarballcache
197 archive_cache_dir = %(here)s/../../data/test/tarballcache
195
198
196 ## change this to unique ID for security
199 ## change this to unique ID for security
197 app_instance_uuid = test
200 app_instance_uuid = test
198
201
199 ## cut off limit for large diffs (size in bytes)
202 ## cut off limit for large diffs (size in bytes)
200 cut_off_limit = 256000
203 cut_off_limit = 256000
201
204
202 ## force https in Kallithea, fixes https redirects, assumes it's always https
205 ## force https in Kallithea, fixes https redirects, assumes it's always https
203 force_https = false
206 force_https = false
204
207
205 ## use Strict-Transport-Security headers
208 ## use Strict-Transport-Security headers
206 use_htsts = false
209 use_htsts = false
207
210
208 ## number of commits stats will parse on each iteration
211 ## number of commits stats will parse on each iteration
209 commit_parse_limit = 25
212 commit_parse_limit = 25
210
213
211 ## path to git executable
214 ## path to git executable
212 git_path = git
215 git_path = git
213
216
214 ## git rev filter option, --all is the default filter, if you need to
217 ## git rev filter option, --all is the default filter, if you need to
215 ## hide all refs in changelog switch this to --branches --tags
218 ## hide all refs in changelog switch this to --branches --tags
216 #git_rev_filter = --branches --tags
219 #git_rev_filter = --branches --tags
217
220
218 ## RSS feed options
221 ## RSS feed options
219 rss_cut_off_limit = 256000
222 rss_cut_off_limit = 256000
220 rss_items_per_page = 10
223 rss_items_per_page = 10
221 rss_include_diff = false
224 rss_include_diff = false
222
225
223 ## options for showing and identifying changesets
226 ## options for showing and identifying changesets
224 show_sha_length = 12
227 show_sha_length = 12
225 #show_revision_number = false
228 #show_revision_number = false
226 show_revision_number = true
229 show_revision_number = true
227
230
228 ## Canonical URL to use when creating full URLs in UI and texts.
231 ## Canonical URL to use when creating full URLs in UI and texts.
229 ## Useful when the site is available under different names or protocols.
232 ## Useful when the site is available under different names or protocols.
230 ## Defaults to what is provided in the WSGI environment.
233 ## Defaults to what is provided in the WSGI environment.
231 #canonical_url = https://kallithea.example.com/repos
234 #canonical_url = https://kallithea.example.com/repos
232
235
233 ## gist URL alias, used to create nicer urls for gist. This should be an
236 ## gist URL alias, used to create nicer urls for gist. This should be an
234 ## url that does rewrites to _admin/gists/<gistid>.
237 ## url that does rewrites to _admin/gists/<gistid>.
235 ## example: http://gist.example.com/{gistid}. Empty means use the internal
238 ## example: http://gist.example.com/{gistid}. Empty means use the internal
236 ## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid>
239 ## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid>
237 gist_alias_url =
240 gist_alias_url =
238
241
239 ## white list of API enabled controllers. This allows to add list of
242 ## white list of API enabled controllers. This allows to add list of
240 ## controllers to which access will be enabled by api_key. eg: to enable
243 ## controllers to which access will be enabled by api_key. eg: to enable
241 ## api access to raw_files put `FilesController:raw`, to enable access to patches
244 ## api access to raw_files put `FilesController:raw`, to enable access to patches
242 ## add `ChangesetController:changeset_patch`. This list should be "," separated
245 ## add `ChangesetController:changeset_patch`. This list should be "," separated
243 ## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
246 ## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
244 ## Recommended settings below are commented out:
247 ## Recommended settings below are commented out:
245 api_access_controllers_whitelist =
248 api_access_controllers_whitelist =
246 # ChangesetController:changeset_patch,
249 # ChangesetController:changeset_patch,
247 # ChangesetController:changeset_raw,
250 # ChangesetController:changeset_raw,
248 # FilesController:raw,
251 # FilesController:raw,
249 # FilesController:archivefile
252 # FilesController:archivefile
250
253
251 ## default encoding used to convert from and to unicode
254 ## default encoding used to convert from and to unicode
252 ## can be also a comma separated list of encoding in case of mixed encodings
255 ## can be also a comma separated list of encoding in case of mixed encodings
253 default_encoding = utf8
256 default_encoding = utf8
254
257
255 ## issue tracker for Kallithea (leave blank to disable, absent for default)
258 ## issue tracker for Kallithea (leave blank to disable, absent for default)
256 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
259 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
257
260
258 ## issue tracking mapping for commits messages
261 ## issue tracking mapping for commits messages
259 ## comment out issue_pat, issue_server, issue_prefix to enable
262 ## comment out issue_pat, issue_server, issue_prefix to enable
260
263
261 ## pattern to get the issues from commit messages
264 ## pattern to get the issues from commit messages
262 ## default one used here is #<numbers> with a regex passive group for `#`
265 ## default one used here is #<numbers> with a regex passive group for `#`
263 ## {id} will be all groups matched from this pattern
266 ## {id} will be all groups matched from this pattern
264
267
265 issue_pat = (?:\s*#)(\d+)
268 issue_pat = (?:\s*#)(\d+)
266
269
267 ## server url to the issue, each {id} will be replaced with match
270 ## server url to the issue, each {id} will be replaced with match
268 ## fetched from the regex and {repo} is replaced with full repository name
271 ## fetched from the regex and {repo} is replaced with full repository name
269 ## including groups {repo_name} is replaced with just name of repo
272 ## including groups {repo_name} is replaced with just name of repo
270
273
271 issue_server_link = https://issues.example.com/{repo}/issue/{id}
274 issue_server_link = https://issues.example.com/{repo}/issue/{id}
272
275
273 ## prefix to add to link to indicate it's an url
276 ## prefix to add to link to indicate it's an url
274 ## #314 will be replaced by <issue_prefix><id>
277 ## #314 will be replaced by <issue_prefix><id>
275
278
276 issue_prefix = #
279 issue_prefix = #
277
280
278 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
281 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
279 ## multiple patterns, to other issues server, wiki or others
282 ## multiple patterns, to other issues server, wiki or others
280 ## below an example how to create a wiki pattern
283 ## below an example how to create a wiki pattern
281 # wiki-some-id -> https://wiki.example.com/some-id
284 # wiki-some-id -> https://wiki.example.com/some-id
282
285
283 #issue_pat_wiki = (?:wiki-)(.+)
286 #issue_pat_wiki = (?:wiki-)(.+)
284 #issue_server_link_wiki = https://wiki.example.com/{id}
287 #issue_server_link_wiki = https://wiki.example.com/{id}
285 #issue_prefix_wiki = WIKI-
288 #issue_prefix_wiki = WIKI-
286
289
287 ## alternative return HTTP header for failed authentication. Default HTTP
290 ## alternative return HTTP header for failed authentication. Default HTTP
288 ## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
291 ## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
289 ## handling that. Set this variable to 403 to return HTTPForbidden
292 ## handling that. Set this variable to 403 to return HTTPForbidden
290 auth_ret_code =
293 auth_ret_code =
291
294
292 ## locking return code. When repository is locked return this HTTP code. 2XX
295 ## locking return code. When repository is locked return this HTTP code. 2XX
293 ## codes don't break the transactions while 4XX codes do
296 ## codes don't break the transactions while 4XX codes do
294 lock_ret_code = 423
297 lock_ret_code = 423
295
298
296 ## allows to change the repository location in settings page
299 ## allows to change the repository location in settings page
297 allow_repo_location_change = True
300 allow_repo_location_change = True
298
301
299 ## allows to setup custom hooks in settings page
302 ## allows to setup custom hooks in settings page
300 allow_custom_hooks_settings = True
303 allow_custom_hooks_settings = True
301
304
302 ## extra extensions for indexing, space separated and without the leading '.'.
305 ## extra extensions for indexing, space separated and without the leading '.'.
303 # index.extensions =
306 # index.extensions =
304 # gemfile
307 # gemfile
305 # lock
308 # lock
306
309
307 ## extra filenames for indexing, space separated
310 ## extra filenames for indexing, space separated
308 # index.filenames =
311 # index.filenames =
309 # .dockerignore
312 # .dockerignore
310 # .editorconfig
313 # .editorconfig
311 # INSTALL
314 # INSTALL
312 # CHANGELOG
315 # CHANGELOG
313
316
314 ####################################
317 ####################################
315 ### CELERY CONFIG ####
318 ### CELERY CONFIG ####
316 ####################################
319 ####################################
317
320
318 use_celery = false
321 use_celery = false
319
322
320 ## Example: connect to the virtual host 'rabbitmqhost' on localhost as rabbitmq:
323 ## Example: connect to the virtual host 'rabbitmqhost' on localhost as rabbitmq:
321 broker.url = amqp://rabbitmq:qewqew@localhost:5672/rabbitmqhost
324 broker.url = amqp://rabbitmq:qewqew@localhost:5672/rabbitmqhost
322
325
323 celery.imports = kallithea.lib.celerylib.tasks
326 celery.imports = kallithea.lib.celerylib.tasks
324 celery.accept.content = pickle
327 celery.accept.content = pickle
325 celery.result.backend = amqp
328 celery.result.backend = amqp
326 celery.result.dburi = amqp://
329 celery.result.dburi = amqp://
327 celery.result.serialier = json
330 celery.result.serialier = json
328
331
329 #celery.send.task.error.emails = true
332 #celery.send.task.error.emails = true
330 #celery.amqp.task.result.expires = 18000
333 #celery.amqp.task.result.expires = 18000
331
334
332 celeryd.concurrency = 2
335 celeryd.concurrency = 2
333 celeryd.max.tasks.per.child = 1
336 celeryd.max.tasks.per.child = 1
334
337
335 ## If true, tasks will never be sent to the queue, but executed locally instead.
338 ## If true, tasks will never be sent to the queue, but executed locally instead.
336 celery.always.eager = false
339 celery.always.eager = false
337
340
338 ####################################
341 ####################################
339 ### BEAKER CACHE ####
342 ### BEAKER CACHE ####
340 ####################################
343 ####################################
341
344
342 #beaker.cache.data_dir = %(here)s/data/cache/data
345 #beaker.cache.data_dir = %(here)s/data/cache/data
343 beaker.cache.data_dir = %(here)s/../../data/test/cache/data
346 beaker.cache.data_dir = %(here)s/../../data/test/cache/data
344 #beaker.cache.lock_dir = %(here)s/data/cache/lock
347 #beaker.cache.lock_dir = %(here)s/data/cache/lock
345 beaker.cache.lock_dir = %(here)s/../../data/test/cache/lock
348 beaker.cache.lock_dir = %(here)s/../../data/test/cache/lock
346
349
347 beaker.cache.regions = short_term,long_term,sql_cache_short
350 beaker.cache.regions = short_term,long_term,sql_cache_short
348
351
349 beaker.cache.short_term.type = memory
352 beaker.cache.short_term.type = memory
350 beaker.cache.short_term.expire = 60
353 beaker.cache.short_term.expire = 60
351 beaker.cache.short_term.key_length = 256
354 beaker.cache.short_term.key_length = 256
352
355
353 beaker.cache.long_term.type = memory
356 beaker.cache.long_term.type = memory
354 beaker.cache.long_term.expire = 36000
357 beaker.cache.long_term.expire = 36000
355 beaker.cache.long_term.key_length = 256
358 beaker.cache.long_term.key_length = 256
356
359
357 beaker.cache.sql_cache_short.type = memory
360 beaker.cache.sql_cache_short.type = memory
358 #beaker.cache.sql_cache_short.expire = 10
361 #beaker.cache.sql_cache_short.expire = 10
359 beaker.cache.sql_cache_short.expire = 1
362 beaker.cache.sql_cache_short.expire = 1
360 beaker.cache.sql_cache_short.key_length = 256
363 beaker.cache.sql_cache_short.key_length = 256
361
364
362 ####################################
365 ####################################
363 ### BEAKER SESSION ####
366 ### BEAKER SESSION ####
364 ####################################
367 ####################################
365
368
366 ## Name of session cookie. Should be unique for a given host and path, even when running
369 ## Name of session cookie. Should be unique for a given host and path, even when running
367 ## on different ports. Otherwise, cookie sessions will be shared and messed up.
370 ## on different ports. Otherwise, cookie sessions will be shared and messed up.
368 beaker.session.key = kallithea
371 beaker.session.key = kallithea
369 ## Sessions should always only be accessible by the browser, not directly by JavaScript.
372 ## Sessions should always only be accessible by the browser, not directly by JavaScript.
370 beaker.session.httponly = true
373 beaker.session.httponly = true
371 ## Session lifetime. 2592000 seconds is 30 days.
374 ## Session lifetime. 2592000 seconds is 30 days.
372 beaker.session.timeout = 2592000
375 beaker.session.timeout = 2592000
373
376
374 ## Server secret used with HMAC to ensure integrity of cookies.
377 ## Server secret used with HMAC to ensure integrity of cookies.
375 beaker.session.secret = {74e0cd75-b339-478b-b129-07dd221def1f}
378 beaker.session.secret = {74e0cd75-b339-478b-b129-07dd221def1f}
376 ## Further, encrypt the data with AES.
379 ## Further, encrypt the data with AES.
377 #beaker.session.encrypt_key = <key_for_encryption>
380 #beaker.session.encrypt_key = <key_for_encryption>
378 #beaker.session.validate_key = <validation_key>
381 #beaker.session.validate_key = <validation_key>
379
382
380 ## Type of storage used for the session, current types are
383 ## Type of storage used for the session, current types are
381 ## dbm, file, memcached, database, and memory.
384 ## dbm, file, memcached, database, and memory.
382
385
383 ## File system storage of session data. (default)
386 ## File system storage of session data. (default)
384 #beaker.session.type = file
387 #beaker.session.type = file
385
388
386 ## Cookie only, store all session data inside the cookie. Requires secure secrets.
389 ## Cookie only, store all session data inside the cookie. Requires secure secrets.
387 #beaker.session.type = cookie
390 #beaker.session.type = cookie
388
391
389 ## Database storage of session data.
392 ## Database storage of session data.
390 #beaker.session.type = ext:database
393 #beaker.session.type = ext:database
391 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/kallithea
394 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/kallithea
392 #beaker.session.table_name = db_session
395 #beaker.session.table_name = db_session
393
396
394 ############################
397 ############################
395 ## ERROR HANDLING SYSTEMS ##
398 ## ERROR HANDLING SYSTEMS ##
396 ############################
399 ############################
397
400
398 ####################
401 ####################
399 ### [appenlight] ###
402 ### [appenlight] ###
400 ####################
403 ####################
401
404
402 ## AppEnlight is tailored to work with Kallithea, see
405 ## AppEnlight is tailored to work with Kallithea, see
403 ## http://appenlight.com for details how to obtain an account
406 ## http://appenlight.com for details how to obtain an account
404 ## you must install python package `appenlight_client` to make it work
407 ## you must install python package `appenlight_client` to make it work
405
408
406 ## appenlight enabled
409 ## appenlight enabled
407 appenlight = false
410 appenlight = false
408
411
409 appenlight.server_url = https://api.appenlight.com
412 appenlight.server_url = https://api.appenlight.com
410 appenlight.api_key = YOUR_API_KEY
413 appenlight.api_key = YOUR_API_KEY
411
414
412 ## TWEAK AMOUNT OF INFO SENT HERE
415 ## TWEAK AMOUNT OF INFO SENT HERE
413
416
414 ## enables 404 error logging (default False)
417 ## enables 404 error logging (default False)
415 appenlight.report_404 = false
418 appenlight.report_404 = false
416
419
417 ## time in seconds after request is considered being slow (default 1)
420 ## time in seconds after request is considered being slow (default 1)
418 appenlight.slow_request_time = 1
421 appenlight.slow_request_time = 1
419
422
420 ## record slow requests in application
423 ## record slow requests in application
421 ## (needs to be enabled for slow datastore recording and time tracking)
424 ## (needs to be enabled for slow datastore recording and time tracking)
422 appenlight.slow_requests = true
425 appenlight.slow_requests = true
423
426
424 ## enable hooking to application loggers
427 ## enable hooking to application loggers
425 #appenlight.logging = true
428 #appenlight.logging = true
426
429
427 ## minimum log level for log capture
430 ## minimum log level for log capture
428 #appenlight.logging.level = WARNING
431 #appenlight.logging.level = WARNING
429
432
430 ## send logs only from erroneous/slow requests
433 ## send logs only from erroneous/slow requests
431 ## (saves API quota for intensive logging)
434 ## (saves API quota for intensive logging)
432 appenlight.logging_on_error = false
435 appenlight.logging_on_error = false
433
436
434 ## list of additional keywords that should be grabbed from environ object
437 ## list of additional keywords that should be grabbed from environ object
435 ## can be string with comma separated list of words in lowercase
438 ## can be string with comma separated list of words in lowercase
436 ## (by default client will always send following info:
439 ## (by default client will always send following info:
437 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
440 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
438 ## start with HTTP* this list be extended with additional keywords here
441 ## start with HTTP* this list be extended with additional keywords here
439 appenlight.environ_keys_whitelist =
442 appenlight.environ_keys_whitelist =
440
443
441 ## list of keywords that should be blanked from request object
444 ## list of keywords that should be blanked from request object
442 ## can be string with comma separated list of words in lowercase
445 ## can be string with comma separated list of words in lowercase
443 ## (by default client will always blank keys that contain following words
446 ## (by default client will always blank keys that contain following words
444 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
447 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
445 ## this list be extended with additional keywords set here
448 ## this list be extended with additional keywords set here
446 appenlight.request_keys_blacklist =
449 appenlight.request_keys_blacklist =
447
450
448 ## list of namespaces that should be ignores when gathering log entries
451 ## list of namespaces that should be ignores when gathering log entries
449 ## can be string with comma separated list of namespaces
452 ## can be string with comma separated list of namespaces
450 ## (by default the client ignores own entries: appenlight_client.client)
453 ## (by default the client ignores own entries: appenlight_client.client)
451 appenlight.log_namespace_blacklist =
454 appenlight.log_namespace_blacklist =
452
455
453 ################
456 ################
454 ### [sentry] ###
457 ### [sentry] ###
455 ################
458 ################
456
459
457 ## sentry is a alternative open source error aggregator
460 ## sentry is a alternative open source error aggregator
458 ## you must install python packages `sentry` and `raven` to enable
461 ## you must install python packages `sentry` and `raven` to enable
459
462
460 sentry.dsn = YOUR_DNS
463 sentry.dsn = YOUR_DNS
461 sentry.servers =
464 sentry.servers =
462 sentry.name =
465 sentry.name =
463 sentry.key =
466 sentry.key =
464 sentry.public_key =
467 sentry.public_key =
465 sentry.secret_key =
468 sentry.secret_key =
466 sentry.project =
469 sentry.project =
467 sentry.site =
470 sentry.site =
468 sentry.include_paths =
471 sentry.include_paths =
469 sentry.exclude_paths =
472 sentry.exclude_paths =
470
473
471 ################################################################################
474 ################################################################################
472 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
475 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
473 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
476 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
474 ## execute malicious code after an exception is raised. ##
477 ## execute malicious code after an exception is raised. ##
475 ################################################################################
478 ################################################################################
476 set debug = false
479 set debug = false
477
480
478 ##################################
481 ##################################
479 ### LOGVIEW CONFIG ###
482 ### LOGVIEW CONFIG ###
480 ##################################
483 ##################################
481
484
482 logview.sqlalchemy = #faa
485 logview.sqlalchemy = #faa
483 logview.pylons.templating = #bfb
486 logview.pylons.templating = #bfb
484 logview.pylons.util = #eee
487 logview.pylons.util = #eee
485
488
486 #########################################################
489 #########################################################
487 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
490 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
488 #########################################################
491 #########################################################
489
492
490 # SQLITE [default]
493 # SQLITE [default]
491 #sqlalchemy.url = sqlite:///%(here)s/kallithea.db?timeout=60
494 #sqlalchemy.url = sqlite:///%(here)s/kallithea.db?timeout=60
492 sqlalchemy.url = sqlite:///%(here)s/kallithea_test.sqlite
495 sqlalchemy.url = sqlite:///%(here)s/kallithea_test.sqlite
493
496
494 # POSTGRESQL
497 # POSTGRESQL
495 #sqlalchemy.url = postgresql://user:pass@localhost/kallithea
498 #sqlalchemy.url = postgresql://user:pass@localhost/kallithea
496
499
497 # MySQL
500 # MySQL
498 #sqlalchemy.url = mysql://user:pass@localhost/kallithea?charset=utf8
501 #sqlalchemy.url = mysql://user:pass@localhost/kallithea?charset=utf8
499
502
500 # see sqlalchemy docs for others
503 # see sqlalchemy docs for others
501
504
502 sqlalchemy.echo = false
505 sqlalchemy.echo = false
503 sqlalchemy.pool_recycle = 3600
506 sqlalchemy.pool_recycle = 3600
504
507
505 ################################
508 ################################
506 ### ALEMBIC CONFIGURATION ####
509 ### ALEMBIC CONFIGURATION ####
507 ################################
510 ################################
508
511
509 [alembic]
512 [alembic]
510 script_location = kallithea:alembic
513 script_location = kallithea:alembic
511
514
512 ################################
515 ################################
513 ### LOGGING CONFIGURATION ####
516 ### LOGGING CONFIGURATION ####
514 ################################
517 ################################
515
518
516 [loggers]
519 [loggers]
517 keys = root, routes, kallithea, sqlalchemy, beaker, templates, whoosh_indexer
520 keys = root, routes, kallithea, sqlalchemy, gearbox, beaker, templates, whoosh_indexer
518
521
519 [handlers]
522 [handlers]
520 keys = console, console_sql
523 keys = console, console_sql
521
524
522 [formatters]
525 [formatters]
523 keys = generic, color_formatter, color_formatter_sql
526 keys = generic, color_formatter, color_formatter_sql
524
527
525 #############
528 #############
526 ## LOGGERS ##
529 ## LOGGERS ##
527 #############
530 #############
528
531
529 [logger_root]
532 [logger_root]
530 level = NOTSET
533 level = NOTSET
531 handlers = console
534 handlers = console
532
535
533 [logger_routes]
536 [logger_routes]
534 level = DEBUG
537 level = DEBUG
535 handlers =
538 handlers =
536 qualname = routes.middleware
539 qualname = routes.middleware
537 ## "level = DEBUG" logs the route matched and routing variables.
540 ## "level = DEBUG" logs the route matched and routing variables.
538 propagate = 1
541 propagate = 1
539
542
540 [logger_beaker]
543 [logger_beaker]
541 level = DEBUG
544 level = DEBUG
542 handlers =
545 handlers =
543 qualname = beaker.container
546 qualname = beaker.container
544 propagate = 1
547 propagate = 1
545
548
546 [logger_templates]
549 [logger_templates]
547 level = INFO
550 level = INFO
548 handlers =
551 handlers =
549 qualname = pylons.templating
552 qualname = pylons.templating
550 propagate = 1
553 propagate = 1
551
554
552 [logger_kallithea]
555 [logger_kallithea]
553 level = DEBUG
556 level = DEBUG
554 handlers =
557 handlers =
555 qualname = kallithea
558 qualname = kallithea
556 propagate = 1
559 propagate = 1
557
560
561 [logger_gearbox]
562 level = DEBUG
563 handlers =
564 qualname = gearbox
565 propagate = 1
566
558 [logger_sqlalchemy]
567 [logger_sqlalchemy]
559 level = INFO
568 level = INFO
560 handlers = console_sql
569 handlers = console_sql
561 qualname = sqlalchemy.engine
570 qualname = sqlalchemy.engine
562 propagate = 0
571 propagate = 0
563
572
564 [logger_whoosh_indexer]
573 [logger_whoosh_indexer]
565 level = DEBUG
574 level = DEBUG
566 handlers =
575 handlers =
567 qualname = whoosh_indexer
576 qualname = whoosh_indexer
568 propagate = 1
577 propagate = 1
569
578
570 ##############
579 ##############
571 ## HANDLERS ##
580 ## HANDLERS ##
572 ##############
581 ##############
573
582
574 [handler_console]
583 [handler_console]
575 class = StreamHandler
584 class = StreamHandler
576 args = (sys.stderr,)
585 args = (sys.stderr,)
577 #level = INFO
586 #level = INFO
578 level = DEBUG
587 level = DEBUG
579 #formatter = generic
588 #formatter = generic
580 formatter = color_formatter
589 formatter = color_formatter
581
590
582 [handler_console_sql]
591 [handler_console_sql]
583 class = StreamHandler
592 class = StreamHandler
584 args = (sys.stderr,)
593 args = (sys.stderr,)
585 level = WARN
594 level = WARN
586 #formatter = generic
595 #formatter = generic
587 formatter = color_formatter_sql
596 formatter = color_formatter_sql
588
597
589 ################
598 ################
590 ## FORMATTERS ##
599 ## FORMATTERS ##
591 ################
600 ################
592
601
593 [formatter_generic]
602 [formatter_generic]
594 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
603 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
595 datefmt = %Y-%m-%d %H:%M:%S
604 datefmt = %Y-%m-%d %H:%M:%S
596
605
597 [formatter_color_formatter]
606 [formatter_color_formatter]
598 class = kallithea.lib.colored_formatter.ColorFormatter
607 class = kallithea.lib.colored_formatter.ColorFormatter
599 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
608 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
600 datefmt = %Y-%m-%d %H:%M:%S
609 datefmt = %Y-%m-%d %H:%M:%S
601
610
602 [formatter_color_formatter_sql]
611 [formatter_color_formatter_sql]
603 class = kallithea.lib.colored_formatter.ColorFormatterSql
612 class = kallithea.lib.colored_formatter.ColorFormatterSql
604 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
613 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
605 datefmt = %Y-%m-%d %H:%M:%S
614 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,121 +1,121 b''
1 #!/bin/sh -e
1 #!/bin/sh -e
2
2
3 if [ $# -lt 2 ] || [ $# -gt 3 ]; then
3 if [ $# -lt 2 ] || [ $# -gt 3 ]; then
4 cat >&2 <<EOD
4 cat >&2 <<EOD
5 usage: $0 CONFIG_FILE FROM_REV [TO_REV]
5 usage: $0 CONFIG_FILE FROM_REV [TO_REV]
6
6
7 Runs a database migration from FROM_REV to TO_REV (default: current
7 Runs a database migration from FROM_REV to TO_REV (default: current
8 working directory parent), using the specified CONFIG_FILE (.ini file).
8 working directory parent), using the specified CONFIG_FILE (.ini file).
9
9
10 Test is run using a clean Kallithea install, in a temporary virtual
10 Test is run using a clean Kallithea install, in a temporary virtual
11 environment. FROM_REV and (optional) TO_REV should be Mercurial revision
11 environment. FROM_REV and (optional) TO_REV should be Mercurial revision
12 identifiers (e.g. changeset hash or a version number tag). The working
12 identifiers (e.g. changeset hash or a version number tag). The working
13 directory is not touched, but the database referenced in the config file
13 directory is not touched, but the database referenced in the config file
14 will be (re)created.
14 will be (re)created.
15
15
16 Only SQLite is available out of the box; for MySQL or PostgreSQL, set
16 Only SQLite is available out of the box; for MySQL or PostgreSQL, set
17 the EXTRA environment variable to the required package(s), and it'll
17 the EXTRA environment variable to the required package(s), and it'll
18 be installed in the virtual environment. (E.g. EXTRA=MySQL-python or
18 be installed in the virtual environment. (E.g. EXTRA=MySQL-python or
19 EXTRA=psycopg2.)
19 EXTRA=psycopg2.)
20
20
21 The temporary directory is not removed, allowing follow-up examination
21 The temporary directory is not removed, allowing follow-up examination
22 of the upgrade results. It is, however, created in /tmp by default,
22 of the upgrade results. It is, however, created in /tmp by default,
23 which many Linux distributions automatically clean at regular intervals.
23 which many Linux distributions automatically clean at regular intervals.
24 EOD
24 EOD
25 exit 1
25 exit 1
26 fi
26 fi
27
27
28 config_file=$(readlink -f "$1")
28 config_file=$(readlink -f "$1")
29 from_rev=$2
29 from_rev=$2
30 to_rev=$3
30 to_rev=$3
31 source_repo=$(dirname "$(dirname "$(readlink -f "$0")")")
31 source_repo=$(dirname "$(dirname "$(readlink -f "$0")")")
32
32
33 announce() {
33 announce() {
34 echo
34 echo
35 echo "$1"
35 echo "$1"
36 echo
36 echo
37 }
37 }
38
38
39 quiet_if_ok() (
39 quiet_if_ok() (
40 local output
40 local output
41 local st
41 local st
42 set +e
42 set +e
43 output=$("$@" < /dev/null 2>&1)
43 output=$("$@" < /dev/null 2>&1)
44 st=$?
44 st=$?
45 if [ $st -ne 0 ]; then
45 if [ $st -ne 0 ]; then
46 echo "$output" >&2
46 echo "$output" >&2
47 echo "Command $@ returned exit status $st." >&2
47 echo "Command $@ returned exit status $st." >&2
48 exit 1
48 exit 1
49 fi
49 fi
50 )
50 )
51
51
52 HG() {
52 HG() {
53 "${HG:-hg}" --repository "$source_repo" "$@"
53 "${HG:-hg}" --repository "$source_repo" "$@"
54 }
54 }
55
55
56 # If upgrading to "current revision", warn if working directory is dirty.
56 # If upgrading to "current revision", warn if working directory is dirty.
57 if [ ! "$to_rev" ] && [ "$(HG status -mard)" ]; then
57 if [ ! "$to_rev" ] && [ "$(HG status -mard)" ]; then
58 announce "Warning: Uncommitted changes in working directory will be ignored!"
58 announce "Warning: Uncommitted changes in working directory will be ignored!"
59 fi
59 fi
60
60
61 from_rev_hash=$(HG id --id --rev "${from_rev:-.}")
61 from_rev_hash=$(HG id --id --rev "${from_rev:-.}")
62 to_rev_hash=$(HG id --id --rev "${to_rev:-.}")
62 to_rev_hash=$(HG id --id --rev "${to_rev:-.}")
63 temp=$(readlink -f "$(mktemp --tmpdir -d 'dbmigrate-test.XXXXXX')")
63 temp=$(readlink -f "$(mktemp --tmpdir -d 'dbmigrate-test.XXXXXX')")
64
64
65 cat <<EOD
65 cat <<EOD
66 Config file: $config_file
66 Config file: $config_file
67 EOD
67 EOD
68 sed -n -e 's/^sqlalchemy\.url *= */Database URL: /p' "$config_file"
68 sed -n -e 's/^sqlalchemy\.url *= */Database URL: /p' "$config_file"
69 cat <<EOD
69 cat <<EOD
70 Working dir: $temp
70 Working dir: $temp
71 Repository: $source_repo
71 Repository: $source_repo
72 Upgrade from: $from_rev_hash (${from_rev:-current})
72 Upgrade from: $from_rev_hash (${from_rev:-current})
73 Upgrade to: $to_rev_hash (${to_rev:-current})
73 Upgrade to: $to_rev_hash (${to_rev:-current})
74 Extra packages: ${EXTRA:-(none)}
74 Extra packages: ${EXTRA:-(none)}
75 EOD
75 EOD
76
76
77 mkdir "$temp/repos" # empty
77 mkdir "$temp/repos" # empty
78
78
79 # Enable caching for old pip versions (this will cache the pip upgrade)
79 # Enable caching for old pip versions (this will cache the pip upgrade)
80 # Newer pip versions cache automatically, and don't use this variable.
80 # Newer pip versions cache automatically, and don't use this variable.
81 if [ ! "$PIP_DOWNLOAD_CACHE" ]; then
81 if [ ! "$PIP_DOWNLOAD_CACHE" ]; then
82 export PIP_DOWNLOAD_CACHE=$HOME/.cache/pip/legacy
82 export PIP_DOWNLOAD_CACHE=$HOME/.cache/pip/legacy
83 fi
83 fi
84
84
85 install_kallithea() {
85 install_kallithea() {
86 local prefix=$1
86 local prefix=$1
87 local rev=$2
87 local rev=$2
88
88
89 announce "Installing Kallithea $rev in $prefix..."
89 announce "Installing Kallithea $rev in $prefix..."
90
90
91 "${VIRTUALENV:-virtualenv}" --quiet "$prefix-env"
91 "${VIRTUALENV:-virtualenv}" --quiet "$prefix-env"
92 HG archive --rev "$rev" "$prefix"
92 HG archive --rev "$rev" "$prefix"
93
93
94 (
94 (
95 cd "$prefix"
95 cd "$prefix"
96 . "$prefix-env/bin/activate"
96 . "$prefix-env/bin/activate"
97 pip install --quiet --upgrade pip setuptools mercurial $EXTRA
97 pip install --quiet --upgrade pip setuptools mercurial $EXTRA
98 pip install --quiet -e .
98 pip install --quiet -e .
99 )
99 )
100 }
100 }
101
101
102 install_kallithea "$temp/from" "$from_rev_hash"
102 install_kallithea "$temp/from" "$from_rev_hash"
103 (
103 (
104 cd "$temp/from"
104 cd "$temp/from"
105 . "$temp/from-env/bin/activate"
105 . "$temp/from-env/bin/activate"
106 announce "Initializing database..."
106 announce "Initializing database..."
107 quiet_if_ok paster setup-db "$config_file" --repos="$temp/repos" --user=doe --email=doe@example.com --password=123456 --no-public-access --force-yes
107 quiet_if_ok gearbox setup-db -c "$config_file" --repos="$temp/repos" --user=doe --email=doe@example.com --password=123456 --no-public-access --force-yes
108 alembic -c "$config_file" current -v
108 alembic -c "$config_file" current -v
109 )
109 )
110
110
111 install_kallithea "$temp/to" "$to_rev_hash"
111 install_kallithea "$temp/to" "$to_rev_hash"
112 (
112 (
113 cd "$temp/to"
113 cd "$temp/to"
114 . "$temp/to-env/bin/activate"
114 . "$temp/to-env/bin/activate"
115
115
116 announce "Commencing database upgrade from shown Alembic revision to head..."
116 announce "Commencing database upgrade from shown Alembic revision to head..."
117 alembic -c "$config_file" current -v
117 alembic -c "$config_file" current -v
118 alembic -c "$config_file" upgrade head
118 alembic -c "$config_file" upgrade head
119 announce "Upgrade complete, now at the shown Alembic revision:"
119 announce "Upgrade complete, now at the shown Alembic revision:"
120 alembic -c "$config_file" current -v
120 alembic -c "$config_file" current -v
121 )
121 )
@@ -1,171 +1,170 b''
1 #!/usr/bin/env python2
1 #!/usr/bin/env python2
2 # -*- coding: utf-8 -*-
2 # -*- coding: utf-8 -*-
3 import os
3 import os
4 import sys
4 import sys
5 import platform
5 import platform
6
6
7 if sys.version_info < (2, 6) or sys.version_info >= (3,):
7 if sys.version_info < (2, 6) or sys.version_info >= (3,):
8 raise Exception('Kallithea requires python 2.6 or 2.7')
8 raise Exception('Kallithea requires python 2.6 or 2.7')
9
9
10
10
11 here = os.path.abspath(os.path.dirname(__file__))
11 here = os.path.abspath(os.path.dirname(__file__))
12
12
13
13
14 def _get_meta_var(name, data, callback_handler=None):
14 def _get_meta_var(name, data, callback_handler=None):
15 import re
15 import re
16 matches = re.compile(r'(?:%s)\s*=\s*(.*)' % name).search(data)
16 matches = re.compile(r'(?:%s)\s*=\s*(.*)' % name).search(data)
17 if matches:
17 if matches:
18 if not callable(callback_handler):
18 if not callable(callback_handler):
19 callback_handler = lambda v: v
19 callback_handler = lambda v: v
20
20
21 return callback_handler(eval(matches.groups()[0]))
21 return callback_handler(eval(matches.groups()[0]))
22
22
23 _meta = open(os.path.join(here, 'kallithea', '__init__.py'), 'rb')
23 _meta = open(os.path.join(here, 'kallithea', '__init__.py'), 'rb')
24 _metadata = _meta.read()
24 _metadata = _meta.read()
25 _meta.close()
25 _meta.close()
26
26
27 callback = lambda V: ('.'.join(map(str, V[:3])) + '.'.join(V[3:]))
27 callback = lambda V: ('.'.join(map(str, V[:3])) + '.'.join(V[3:]))
28 __version__ = _get_meta_var('VERSION', _metadata, callback)
28 __version__ = _get_meta_var('VERSION', _metadata, callback)
29 __license__ = _get_meta_var('__license__', _metadata)
29 __license__ = _get_meta_var('__license__', _metadata)
30 __author__ = _get_meta_var('__author__', _metadata)
30 __author__ = _get_meta_var('__author__', _metadata)
31 __url__ = _get_meta_var('__url__', _metadata)
31 __url__ = _get_meta_var('__url__', _metadata)
32 # defines current platform
32 # defines current platform
33 __platform__ = platform.system()
33 __platform__ = platform.system()
34
34
35 is_windows = __platform__ in ['Windows']
35 is_windows = __platform__ in ['Windows']
36
36
37 requirements = [
37 requirements = [
38 "alembic>=0.8.0,<0.9",
38 "alembic>=0.8.0,<0.9",
39 "GearBox<1",
39 "waitress>=0.8.8,<1.0",
40 "waitress>=0.8.8,<1.0",
40 "webob>=1.7,<2",
41 "webob>=1.7,<2",
41 "Pylons>=1.0.0,<=1.0.2",
42 "Pylons>=1.0.0,<=1.0.2",
42 "Beaker>=1.7.0,<2",
43 "Beaker>=1.7.0,<2",
43 "WebHelpers==1.3",
44 "WebHelpers==1.3",
44 "formencode>=1.2.4,<=1.2.6",
45 "formencode>=1.2.4,<=1.2.6",
45 "SQLAlchemy>=1.0,<1.1",
46 "SQLAlchemy>=1.0,<1.1",
46 "Mako>=0.9.0,<=1.0.0",
47 "Mako>=0.9.0,<=1.0.0",
47 "pygments>=1.5",
48 "pygments>=1.5",
48 "whoosh>=2.5.0,<=2.5.7",
49 "whoosh>=2.5.0,<=2.5.7",
49 "celery>=3.1,<3.2",
50 "celery>=3.1,<3.2",
50 "babel>=0.9.6,<2.4",
51 "babel>=0.9.6,<2.4",
51 "python-dateutil>=1.5.0,<2.0.0",
52 "python-dateutil>=1.5.0,<2.0.0",
52 "markdown==2.2.1",
53 "markdown==2.2.1",
53 "docutils>=0.8.1",
54 "docutils>=0.8.1",
54 "URLObject==2.3.4",
55 "URLObject==2.3.4",
55 "Routes==1.13",
56 "Routes==1.13",
56 "dulwich>=0.14.1",
57 "dulwich>=0.14.1",
57 "mercurial>=2.9,<4.2",
58 "mercurial>=2.9,<4.2",
58 ]
59 ]
59
60
60 if sys.version_info < (2, 7):
61 if sys.version_info < (2, 7):
61 requirements.append("importlib==1.0.1")
62 requirements.append("importlib==1.0.1")
62 requirements.append("argparse")
63 requirements.append("argparse")
63
64
64 if not is_windows:
65 if not is_windows:
65 requirements.append("bcrypt>=3.1.0")
66 requirements.append("bcrypt>=3.1.0")
66
67
67 dependency_links = [
68 dependency_links = [
68 ]
69 ]
69
70
70 classifiers = [
71 classifiers = [
71 'Development Status :: 4 - Beta',
72 'Development Status :: 4 - Beta',
72 'Environment :: Web Environment',
73 'Environment :: Web Environment',
73 'Framework :: Pylons',
74 'Framework :: Pylons',
74 'Intended Audience :: Developers',
75 'Intended Audience :: Developers',
75 'License :: OSI Approved :: GNU General Public License (GPL)',
76 'License :: OSI Approved :: GNU General Public License (GPL)',
76 'Operating System :: OS Independent',
77 'Operating System :: OS Independent',
77 'Programming Language :: Python',
78 'Programming Language :: Python',
78 'Programming Language :: Python :: 2.6',
79 'Programming Language :: Python :: 2.6',
79 'Programming Language :: Python :: 2.7',
80 'Programming Language :: Python :: 2.7',
80 'Topic :: Software Development :: Version Control',
81 'Topic :: Software Development :: Version Control',
81 ]
82 ]
82
83
83
84
84 # additional files from project that goes somewhere in the filesystem
85 # additional files from project that goes somewhere in the filesystem
85 # relative to sys.prefix
86 # relative to sys.prefix
86 data_files = []
87 data_files = []
87
88
88 description = ('Kallithea is a fast and powerful management tool '
89 description = ('Kallithea is a fast and powerful management tool '
89 'for Mercurial and Git with a built in push/pull server, '
90 'for Mercurial and Git with a built in push/pull server, '
90 'full text search and code-review.')
91 'full text search and code-review.')
91
92
92 keywords = ' '.join([
93 keywords = ' '.join([
93 'kallithea', 'mercurial', 'git', 'code review',
94 'kallithea', 'mercurial', 'git', 'code review',
94 'repo groups', 'ldap', 'repository management', 'hgweb replacement',
95 'repo groups', 'ldap', 'repository management', 'hgweb replacement',
95 'hgwebdir', 'gitweb replacement', 'serving hgweb',
96 'hgwebdir', 'gitweb replacement', 'serving hgweb',
96 ])
97 ])
97
98
98 # long description
99 # long description
99 README_FILE = 'README.rst'
100 README_FILE = 'README.rst'
100 try:
101 try:
101 long_description = open(README_FILE).read()
102 long_description = open(README_FILE).read()
102 except IOError as err:
103 except IOError as err:
103 sys.stderr.write(
104 sys.stderr.write(
104 "[WARNING] Cannot find file specified as long_description (%s)\n"
105 "[WARNING] Cannot find file specified as long_description (%s)\n"
105 % README_FILE
106 % README_FILE
106 )
107 )
107 long_description = description
108 long_description = description
108
109
109 import setuptools
110 import setuptools
110
111
111 # monkey patch setuptools to use distutils owner/group functionality
112 # monkey patch setuptools to use distutils owner/group functionality
112 from setuptools.command import sdist
113 from setuptools.command import sdist
113 sdist_org = sdist.sdist
114 sdist_org = sdist.sdist
114 class sdist_new(sdist_org):
115 class sdist_new(sdist_org):
115 def initialize_options(self):
116 def initialize_options(self):
116 sdist_org.initialize_options(self)
117 sdist_org.initialize_options(self)
117 self.owner = self.group = 'root'
118 self.owner = self.group = 'root'
118 sdist.sdist = sdist_new
119 sdist.sdist = sdist_new
119
120
120 packages = setuptools.find_packages(exclude=['ez_setup'])
121 packages = setuptools.find_packages(exclude=['ez_setup'])
121
122
122 setuptools.setup(
123 setuptools.setup(
123 name='Kallithea',
124 name='Kallithea',
124 version=__version__,
125 version=__version__,
125 description=description,
126 description=description,
126 long_description=long_description,
127 long_description=long_description,
127 keywords=keywords,
128 keywords=keywords,
128 license=__license__,
129 license=__license__,
129 author=__author__,
130 author=__author__,
130 author_email='kallithea@sfconservancy.org',
131 author_email='kallithea@sfconservancy.org',
131 dependency_links=dependency_links,
132 dependency_links=dependency_links,
132 url=__url__,
133 url=__url__,
133 install_requires=requirements,
134 install_requires=requirements,
134 classifiers=classifiers,
135 classifiers=classifiers,
135 setup_requires=['PasteScript>=1.6.3'],
136 data_files=data_files,
136 data_files=data_files,
137 packages=packages,
137 packages=packages,
138 include_package_data=True,
138 include_package_data=True,
139 message_extractors={'kallithea': [
139 message_extractors={'kallithea': [
140 ('**.py', 'python', None),
140 ('**.py', 'python', None),
141 ('templates/**.mako', 'mako', {'input_encoding': 'utf-8'}),
141 ('templates/**.mako', 'mako', {'input_encoding': 'utf-8'}),
142 ('templates/**.html', 'mako', {'input_encoding': 'utf-8'}),
142 ('templates/**.html', 'mako', {'input_encoding': 'utf-8'}),
143 ('public/**', 'ignore', None)]},
143 ('public/**', 'ignore', None)]},
144 zip_safe=False,
144 zip_safe=False,
145 paster_plugins=['PasteScript', 'Pylons'],
146 entry_points="""
145 entry_points="""
147 [console_scripts]
146 [console_scripts]
148 kallithea-api = kallithea.bin.kallithea_api:main
147 kallithea-api = kallithea.bin.kallithea_api:main
149 kallithea-gist = kallithea.bin.kallithea_gist:main
148 kallithea-gist = kallithea.bin.kallithea_gist:main
150 kallithea-config = kallithea.bin.kallithea_config:main
149 kallithea-config = kallithea.bin.kallithea_config:main
151
150
152 [paste.app_factory]
151 [paste.app_factory]
153 main = kallithea.config.middleware:make_app
152 main = kallithea.config.middleware:make_app
154
153
155 [paste.app_install]
154 [paste.app_install]
156 main = pylons.util:PylonsInstaller
155 main = pylons.util:PylonsInstaller
157
156
158 [paste.global_paster_command]
157 [gearbox.commands]
159 setup-db=kallithea.lib.paster_commands.setup_db:Command
158 setup-db=kallithea.lib.paster_commands.setup_db:Command
160 cleanup-repos=kallithea.lib.paster_commands.cleanup:Command
159 cleanup-repos=kallithea.lib.paster_commands.cleanup:Command
161 update-repoinfo=kallithea.lib.paster_commands.update_repoinfo:Command
160 update-repoinfo=kallithea.lib.paster_commands.update_repoinfo:Command
162 make-rcext=kallithea.lib.paster_commands.make_rcextensions:Command
161 make-rcext=kallithea.lib.paster_commands.make_rcextensions:Command
163 repo-scan=kallithea.lib.paster_commands.repo_scan:Command
162 repo-scan=kallithea.lib.paster_commands.repo_scan:Command
164 cache-keys=kallithea.lib.paster_commands.cache_keys:Command
163 cache-keys=kallithea.lib.paster_commands.cache_keys:Command
165 ishell=kallithea.lib.paster_commands.ishell:Command
164 ishell=kallithea.lib.paster_commands.ishell:Command
166 make-index=kallithea.lib.paster_commands.make_index:Command
165 make-index=kallithea.lib.paster_commands.make_index:Command
167 upgrade-db=kallithea.lib.dbmigrate:UpgradeDb
166 upgrade-db=kallithea.lib.dbmigrate:UpgradeDb
168 celeryd=kallithea.lib.paster_commands.celeryd:Command
167 celeryd=kallithea.lib.paster_commands.celeryd:Command
169 install-iis=kallithea.lib.paster_commands.install_iis:Command
168 install-iis=kallithea.lib.paster_commands.install_iis:Command
170 """,
169 """,
171 )
170 )
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now