##// 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 3 # Kallithea - Development config: #
4 4 # listening on *:5000 #
5 5 # sqlite and kallithea.db #
6 6 # initial_repo_scan = true #
7 7 # set debug = true #
8 8 # verbose and colorful logging #
9 9 # #
10 10 # The %(here)s variable will be replaced with the parent directory of this file#
11 11 ################################################################################
12 12 ################################################################################
13 13
14 14 [DEFAULT]
15 15 debug = true
16 16 pdebug = false
17 17
18 18 ################################################################################
19 19 ## Email settings ##
20 20 ## ##
21 21 ## Refer to the documentation ("Email settings") for more details. ##
22 22 ## ##
23 23 ## It is recommended to use a valid sender address that passes access ##
24 24 ## validation and spam filtering in mail servers. ##
25 25 ################################################################################
26 26
27 27 ## 'From' header for application emails. You can optionally add a name.
28 28 ## Default:
29 29 #app_email_from = Kallithea
30 30 ## Examples:
31 31 #app_email_from = Kallithea <kallithea-noreply@example.com>
32 32 #app_email_from = kallithea-noreply@example.com
33 33
34 34 ## Subject prefix for application emails.
35 35 ## A space between this prefix and the real subject is automatically added.
36 36 ## Default:
37 37 #email_prefix =
38 38 ## Example:
39 39 #email_prefix = [Kallithea]
40 40
41 41 ## Recipients for error emails and fallback recipients of application mails.
42 42 ## Multiple addresses can be specified, space-separated.
43 43 ## Only addresses are allowed, do not add any name part.
44 44 ## Default:
45 45 #email_to =
46 46 ## Examples:
47 47 #email_to = admin@example.com
48 48 #email_to = admin@example.com another_admin@example.com
49 49
50 50 ## 'From' header for error emails. You can optionally add a name.
51 51 ## Default:
52 52 #error_email_from = pylons@yourapp.com
53 53 ## Examples:
54 54 #error_email_from = Kallithea Errors <kallithea-noreply@example.com>
55 55 #error_email_from = paste_error@example.com
56 56
57 57 ## SMTP server settings
58 58 ## If specifying credentials, make sure to use secure connections.
59 59 ## Default: Send unencrypted unauthenticated mails to the specified smtp_server.
60 60 ## For "SSL", use smtp_use_ssl = true and smtp_port = 465.
61 61 ## For "STARTTLS", use smtp_use_tls = true and smtp_port = 587.
62 62 #smtp_server = smtp.example.com
63 63 #smtp_username =
64 64 #smtp_password =
65 65 #smtp_port = 25
66 66 #smtp_use_ssl = false
67 67 #smtp_use_tls = false
68 68
69 69 [server:main]
70 ## PASTE ##
71 #use = egg:Paste#http
70 ## Gearbox default web server ##
71 #use = egg:gearbox#wsgiref
72 72 ## nr of worker threads to spawn
73 73 #threadpool_workers = 1
74 74 ## max request before thread respawn
75 75 #threadpool_max_requests = 100
76 76 ## option to use threads of process
77 77 #use_threadpool = true
78 78
79 ## Gearbox gevent web server ##
80 #use = egg:gearbox#gevent
81
79 82 ## WAITRESS ##
80 83 use = egg:waitress#main
81 84 ## number of worker threads
82 85 threads = 1
83 86 ## MAX BODY SIZE 100GB
84 87 max_request_body_size = 107374182400
85 88 ## use poll instead of select, fixes fd limits, may not work on old
86 89 ## windows systems.
87 90 #asyncore_use_poll = True
88 91
89 92 ## GUNICORN ##
90 93 #use = egg:gunicorn#main
91 94 ## number of process workers. You must set `instance_id = *` when this option
92 95 ## is set to more than one worker
93 96 #workers = 1
94 97 ## process name
95 98 #proc_name = kallithea
96 99 ## type of worker class, one of sync, eventlet, gevent, tornado
97 100 ## recommended for bigger setup is using of of other than sync one
98 101 #worker_class = sync
99 102 #max_requests = 1000
100 103 ## amount of time a worker can handle request before it gets killed and
101 104 ## restarted
102 105 #timeout = 3600
103 106
104 107 ## UWSGI ##
105 108 ## run with uwsgi --ini-paste-logged <inifile.ini>
106 109 #[uwsgi]
107 110 #socket = /tmp/uwsgi.sock
108 111 #master = true
109 112 #http = 127.0.0.1:5000
110 113
111 114 ## set as deamon and redirect all output to file
112 115 #daemonize = ./uwsgi_kallithea.log
113 116
114 117 ## master process PID
115 118 #pidfile = ./uwsgi_kallithea.pid
116 119
117 120 ## stats server with workers statistics, use uwsgitop
118 121 ## for monitoring, `uwsgitop 127.0.0.1:1717`
119 122 #stats = 127.0.0.1:1717
120 123 #memory-report = true
121 124
122 125 ## log 5XX errors
123 126 #log-5xx = true
124 127
125 128 ## Set the socket listen queue size.
126 129 #listen = 256
127 130
128 131 ## Gracefully Reload workers after the specified amount of managed requests
129 132 ## (avoid memory leaks).
130 133 #max-requests = 1000
131 134
132 135 ## enable large buffers
133 136 #buffer-size = 65535
134 137
135 138 ## socket and http timeouts ##
136 139 #http-timeout = 3600
137 140 #socket-timeout = 3600
138 141
139 142 ## Log requests slower than the specified number of milliseconds.
140 143 #log-slow = 10
141 144
142 145 ## Exit if no app can be loaded.
143 146 #need-app = true
144 147
145 148 ## Set lazy mode (load apps in workers instead of master).
146 149 #lazy = true
147 150
148 151 ## scaling ##
149 152 ## set cheaper algorithm to use, if not set default will be used
150 153 #cheaper-algo = spare
151 154
152 155 ## minimum number of workers to keep at all times
153 156 #cheaper = 1
154 157
155 158 ## number of workers to spawn at startup
156 159 #cheaper-initial = 1
157 160
158 161 ## maximum number of workers that can be spawned
159 162 #workers = 4
160 163
161 164 ## how many workers should be spawned at a time
162 165 #cheaper-step = 1
163 166
164 167 ## COMMON ##
165 168 #host = 127.0.0.1
166 169 host = 0.0.0.0
167 170 port = 5000
168 171
169 172 ## middleware for hosting the WSGI application under a URL prefix
170 173 #[filter:proxy-prefix]
171 174 #use = egg:PasteDeploy#prefix
172 175 #prefix = /<your-prefix>
173 176
174 177 [app:main]
175 178 use = egg:kallithea
176 179 ## enable proxy prefix middleware
177 180 #filter-with = proxy-prefix
178 181
179 182 full_stack = true
180 183 static_files = true
181 184 ## Available Languages:
182 185 ## cs de fr hu ja nl_BE pl pt_BR ru sk zh_CN zh_TW
183 186 lang =
184 187 cache_dir = %(here)s/data
185 188 index_dir = %(here)s/data/index
186 189
187 190 ## perform a full repository scan on each server start, this should be
188 191 ## set to false after first startup, to allow faster server restarts.
189 192 #initial_repo_scan = false
190 193 initial_repo_scan = true
191 194
192 195 ## uncomment and set this path to use archive download cache
193 196 archive_cache_dir = %(here)s/tarballcache
194 197
195 198 ## change this to unique ID for security
196 199 app_instance_uuid = development-not-secret
197 200
198 201 ## cut off limit for large diffs (size in bytes)
199 202 cut_off_limit = 256000
200 203
201 204 ## force https in Kallithea, fixes https redirects, assumes it's always https
202 205 force_https = false
203 206
204 207 ## use Strict-Transport-Security headers
205 208 use_htsts = false
206 209
207 210 ## number of commits stats will parse on each iteration
208 211 commit_parse_limit = 25
209 212
210 213 ## path to git executable
211 214 git_path = git
212 215
213 216 ## git rev filter option, --all is the default filter, if you need to
214 217 ## hide all refs in changelog switch this to --branches --tags
215 218 #git_rev_filter = --branches --tags
216 219
217 220 ## RSS feed options
218 221 rss_cut_off_limit = 256000
219 222 rss_items_per_page = 10
220 223 rss_include_diff = false
221 224
222 225 ## options for showing and identifying changesets
223 226 show_sha_length = 12
224 227 show_revision_number = false
225 228
226 229 ## Canonical URL to use when creating full URLs in UI and texts.
227 230 ## Useful when the site is available under different names or protocols.
228 231 ## Defaults to what is provided in the WSGI environment.
229 232 #canonical_url = https://kallithea.example.com/repos
230 233
231 234 ## gist URL alias, used to create nicer urls for gist. This should be an
232 235 ## url that does rewrites to _admin/gists/<gistid>.
233 236 ## example: http://gist.example.com/{gistid}. Empty means use the internal
234 237 ## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid>
235 238 gist_alias_url =
236 239
237 240 ## white list of API enabled controllers. This allows to add list of
238 241 ## controllers to which access will be enabled by api_key. eg: to enable
239 242 ## api access to raw_files put `FilesController:raw`, to enable access to patches
240 243 ## add `ChangesetController:changeset_patch`. This list should be "," separated
241 244 ## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
242 245 ## Recommended settings below are commented out:
243 246 api_access_controllers_whitelist =
244 247 # ChangesetController:changeset_patch,
245 248 # ChangesetController:changeset_raw,
246 249 # FilesController:raw,
247 250 # FilesController:archivefile
248 251
249 252 ## default encoding used to convert from and to unicode
250 253 ## can be also a comma separated list of encoding in case of mixed encodings
251 254 default_encoding = utf8
252 255
253 256 ## issue tracker for Kallithea (leave blank to disable, absent for default)
254 257 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
255 258
256 259 ## issue tracking mapping for commits messages
257 260 ## comment out issue_pat, issue_server, issue_prefix to enable
258 261
259 262 ## pattern to get the issues from commit messages
260 263 ## default one used here is #<numbers> with a regex passive group for `#`
261 264 ## {id} will be all groups matched from this pattern
262 265
263 266 issue_pat = (?:\s*#)(\d+)
264 267
265 268 ## server url to the issue, each {id} will be replaced with match
266 269 ## fetched from the regex and {repo} is replaced with full repository name
267 270 ## including groups {repo_name} is replaced with just name of repo
268 271
269 272 issue_server_link = https://issues.example.com/{repo}/issue/{id}
270 273
271 274 ## prefix to add to link to indicate it's an url
272 275 ## #314 will be replaced by <issue_prefix><id>
273 276
274 277 issue_prefix = #
275 278
276 279 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
277 280 ## multiple patterns, to other issues server, wiki or others
278 281 ## below an example how to create a wiki pattern
279 282 # wiki-some-id -> https://wiki.example.com/some-id
280 283
281 284 #issue_pat_wiki = (?:wiki-)(.+)
282 285 #issue_server_link_wiki = https://wiki.example.com/{id}
283 286 #issue_prefix_wiki = WIKI-
284 287
285 288 ## alternative return HTTP header for failed authentication. Default HTTP
286 289 ## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
287 290 ## handling that. Set this variable to 403 to return HTTPForbidden
288 291 auth_ret_code =
289 292
290 293 ## locking return code. When repository is locked return this HTTP code. 2XX
291 294 ## codes don't break the transactions while 4XX codes do
292 295 lock_ret_code = 423
293 296
294 297 ## allows to change the repository location in settings page
295 298 allow_repo_location_change = True
296 299
297 300 ## allows to setup custom hooks in settings page
298 301 allow_custom_hooks_settings = True
299 302
300 303 ## extra extensions for indexing, space separated and without the leading '.'.
301 304 # index.extensions =
302 305 # gemfile
303 306 # lock
304 307
305 308 ## extra filenames for indexing, space separated
306 309 # index.filenames =
307 310 # .dockerignore
308 311 # .editorconfig
309 312 # INSTALL
310 313 # CHANGELOG
311 314
312 315 ####################################
313 316 ### CELERY CONFIG ####
314 317 ####################################
315 318
316 319 use_celery = false
317 320
318 321 ## Example: connect to the virtual host 'rabbitmqhost' on localhost as rabbitmq:
319 322 broker.url = amqp://rabbitmq:qewqew@localhost:5672/rabbitmqhost
320 323
321 324 celery.imports = kallithea.lib.celerylib.tasks
322 325 celery.accept.content = pickle
323 326 celery.result.backend = amqp
324 327 celery.result.dburi = amqp://
325 328 celery.result.serialier = json
326 329
327 330 #celery.send.task.error.emails = true
328 331 #celery.amqp.task.result.expires = 18000
329 332
330 333 celeryd.concurrency = 2
331 334 celeryd.max.tasks.per.child = 1
332 335
333 336 ## If true, tasks will never be sent to the queue, but executed locally instead.
334 337 celery.always.eager = false
335 338
336 339 ####################################
337 340 ### BEAKER CACHE ####
338 341 ####################################
339 342
340 343 beaker.cache.data_dir = %(here)s/data/cache/data
341 344 beaker.cache.lock_dir = %(here)s/data/cache/lock
342 345
343 346 beaker.cache.regions = short_term,long_term,sql_cache_short
344 347
345 348 beaker.cache.short_term.type = memory
346 349 beaker.cache.short_term.expire = 60
347 350 beaker.cache.short_term.key_length = 256
348 351
349 352 beaker.cache.long_term.type = memory
350 353 beaker.cache.long_term.expire = 36000
351 354 beaker.cache.long_term.key_length = 256
352 355
353 356 beaker.cache.sql_cache_short.type = memory
354 357 beaker.cache.sql_cache_short.expire = 10
355 358 beaker.cache.sql_cache_short.key_length = 256
356 359
357 360 ####################################
358 361 ### BEAKER SESSION ####
359 362 ####################################
360 363
361 364 ## Name of session cookie. Should be unique for a given host and path, even when running
362 365 ## on different ports. Otherwise, cookie sessions will be shared and messed up.
363 366 beaker.session.key = kallithea
364 367 ## Sessions should always only be accessible by the browser, not directly by JavaScript.
365 368 beaker.session.httponly = true
366 369 ## Session lifetime. 2592000 seconds is 30 days.
367 370 beaker.session.timeout = 2592000
368 371
369 372 ## Server secret used with HMAC to ensure integrity of cookies.
370 373 beaker.session.secret = development-not-secret
371 374 ## Further, encrypt the data with AES.
372 375 #beaker.session.encrypt_key = <key_for_encryption>
373 376 #beaker.session.validate_key = <validation_key>
374 377
375 378 ## Type of storage used for the session, current types are
376 379 ## dbm, file, memcached, database, and memory.
377 380
378 381 ## File system storage of session data. (default)
379 382 #beaker.session.type = file
380 383
381 384 ## Cookie only, store all session data inside the cookie. Requires secure secrets.
382 385 #beaker.session.type = cookie
383 386
384 387 ## Database storage of session data.
385 388 #beaker.session.type = ext:database
386 389 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/kallithea
387 390 #beaker.session.table_name = db_session
388 391
389 392 ############################
390 393 ## ERROR HANDLING SYSTEMS ##
391 394 ############################
392 395
393 396 ####################
394 397 ### [appenlight] ###
395 398 ####################
396 399
397 400 ## AppEnlight is tailored to work with Kallithea, see
398 401 ## http://appenlight.com for details how to obtain an account
399 402 ## you must install python package `appenlight_client` to make it work
400 403
401 404 ## appenlight enabled
402 405 appenlight = false
403 406
404 407 appenlight.server_url = https://api.appenlight.com
405 408 appenlight.api_key = YOUR_API_KEY
406 409
407 410 ## TWEAK AMOUNT OF INFO SENT HERE
408 411
409 412 ## enables 404 error logging (default False)
410 413 appenlight.report_404 = false
411 414
412 415 ## time in seconds after request is considered being slow (default 1)
413 416 appenlight.slow_request_time = 1
414 417
415 418 ## record slow requests in application
416 419 ## (needs to be enabled for slow datastore recording and time tracking)
417 420 appenlight.slow_requests = true
418 421
419 422 ## enable hooking to application loggers
420 423 #appenlight.logging = true
421 424
422 425 ## minimum log level for log capture
423 426 #appenlight.logging.level = WARNING
424 427
425 428 ## send logs only from erroneous/slow requests
426 429 ## (saves API quota for intensive logging)
427 430 appenlight.logging_on_error = false
428 431
429 432 ## list of additional keywords that should be grabbed from environ object
430 433 ## can be string with comma separated list of words in lowercase
431 434 ## (by default client will always send following info:
432 435 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
433 436 ## start with HTTP* this list be extended with additional keywords here
434 437 appenlight.environ_keys_whitelist =
435 438
436 439 ## list of keywords that should be blanked from request object
437 440 ## can be string with comma separated list of words in lowercase
438 441 ## (by default client will always blank keys that contain following words
439 442 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
440 443 ## this list be extended with additional keywords set here
441 444 appenlight.request_keys_blacklist =
442 445
443 446 ## list of namespaces that should be ignores when gathering log entries
444 447 ## can be string with comma separated list of namespaces
445 448 ## (by default the client ignores own entries: appenlight_client.client)
446 449 appenlight.log_namespace_blacklist =
447 450
448 451 ################
449 452 ### [sentry] ###
450 453 ################
451 454
452 455 ## sentry is a alternative open source error aggregator
453 456 ## you must install python packages `sentry` and `raven` to enable
454 457
455 458 sentry.dsn = YOUR_DNS
456 459 sentry.servers =
457 460 sentry.name =
458 461 sentry.key =
459 462 sentry.public_key =
460 463 sentry.secret_key =
461 464 sentry.project =
462 465 sentry.site =
463 466 sentry.include_paths =
464 467 sentry.exclude_paths =
465 468
466 469 ################################################################################
467 470 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
468 471 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
469 472 ## execute malicious code after an exception is raised. ##
470 473 ################################################################################
471 474 #set debug = false
472 475 set debug = true
473 476
474 477 ##################################
475 478 ### LOGVIEW CONFIG ###
476 479 ##################################
477 480
478 481 logview.sqlalchemy = #faa
479 482 logview.pylons.templating = #bfb
480 483 logview.pylons.util = #eee
481 484
482 485 #########################################################
483 486 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
484 487 #########################################################
485 488
486 489 # SQLITE [default]
487 490 sqlalchemy.url = sqlite:///%(here)s/kallithea.db?timeout=60
488 491
489 492 # POSTGRESQL
490 493 #sqlalchemy.url = postgresql://user:pass@localhost/kallithea
491 494
492 495 # MySQL
493 496 #sqlalchemy.url = mysql://user:pass@localhost/kallithea?charset=utf8
494 497
495 498 # see sqlalchemy docs for others
496 499
497 500 sqlalchemy.echo = false
498 501 sqlalchemy.pool_recycle = 3600
499 502
500 503 ################################
501 504 ### ALEMBIC CONFIGURATION ####
502 505 ################################
503 506
504 507 [alembic]
505 508 script_location = kallithea:alembic
506 509
507 510 ################################
508 511 ### LOGGING CONFIGURATION ####
509 512 ################################
510 513
511 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 517 [handlers]
515 518 keys = console, console_sql
516 519
517 520 [formatters]
518 521 keys = generic, color_formatter, color_formatter_sql
519 522
520 523 #############
521 524 ## LOGGERS ##
522 525 #############
523 526
524 527 [logger_root]
525 528 level = NOTSET
526 529 handlers = console
527 530
528 531 [logger_routes]
529 532 level = DEBUG
530 533 handlers =
531 534 qualname = routes.middleware
532 535 ## "level = DEBUG" logs the route matched and routing variables.
533 536 propagate = 1
534 537
535 538 [logger_beaker]
536 539 level = DEBUG
537 540 handlers =
538 541 qualname = beaker.container
539 542 propagate = 1
540 543
541 544 [logger_templates]
542 545 level = INFO
543 546 handlers =
544 547 qualname = pylons.templating
545 548 propagate = 1
546 549
547 550 [logger_kallithea]
548 551 level = DEBUG
549 552 handlers =
550 553 qualname = kallithea
551 554 propagate = 1
552 555
556 [logger_gearbox]
557 level = DEBUG
558 handlers =
559 qualname = gearbox
560 propagate = 1
561
553 562 [logger_sqlalchemy]
554 563 level = INFO
555 564 handlers = console_sql
556 565 qualname = sqlalchemy.engine
557 566 propagate = 0
558 567
559 568 [logger_whoosh_indexer]
560 569 level = DEBUG
561 570 handlers =
562 571 qualname = whoosh_indexer
563 572 propagate = 1
564 573
565 574 ##############
566 575 ## HANDLERS ##
567 576 ##############
568 577
569 578 [handler_console]
570 579 class = StreamHandler
571 580 args = (sys.stderr,)
572 581 #level = INFO
573 582 level = DEBUG
574 583 #formatter = generic
575 584 formatter = color_formatter
576 585
577 586 [handler_console_sql]
578 587 class = StreamHandler
579 588 args = (sys.stderr,)
580 589 #level = WARN
581 590 level = DEBUG
582 591 #formatter = generic
583 592 formatter = color_formatter_sql
584 593
585 594 ################
586 595 ## FORMATTERS ##
587 596 ################
588 597
589 598 [formatter_generic]
590 599 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
591 600 datefmt = %Y-%m-%d %H:%M:%S
592 601
593 602 [formatter_color_formatter]
594 603 class = kallithea.lib.colored_formatter.ColorFormatter
595 604 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
596 605 datefmt = %Y-%m-%d %H:%M:%S
597 606
598 607 [formatter_color_formatter_sql]
599 608 class = kallithea.lib.colored_formatter.ColorFormatterSql
600 609 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
601 610 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,227 +1,227 b''
1 1 .. _contributing:
2 2
3 3 =========================
4 4 Contributing to Kallithea
5 5 =========================
6 6
7 7 Kallithea is developed and maintained by its users. Please join us and scratch
8 8 your own itch.
9 9
10 10
11 11 Infrastructure
12 12 --------------
13 13
14 14 The main repository is hosted on Our Own Kallithea (aka OOK) at
15 15 https://kallithea-scm.org/repos/kallithea/, our self-hosted instance
16 16 of Kallithea.
17 17
18 18 For now, we use Bitbucket_ for `pull requests`_ and `issue tracking`_. The
19 19 issue tracker is for tracking bugs, not for support, discussion, or ideas --
20 20 please use the `mailing list`_ or :ref:`IRC <readme>` to reach the community.
21 21
22 22 We use Weblate_ to translate the user interface messages into languages other
23 23 than English. Join our project on `Hosted Weblate`_ to help us.
24 24 To register, you can use your Bitbucket or GitHub account. See :ref:`translations`
25 25 for more details.
26 26
27 27
28 28 Getting started
29 29 ---------------
30 30
31 31 To get started with development::
32 32
33 33 hg clone https://kallithea-scm.org/repos/kallithea
34 34 cd kallithea
35 35 virtualenv ../kallithea-venv
36 36 source ../kallithea-venv/bin/activate
37 37 pip install --upgrade pip setuptools
38 38 pip install -e .
39 paster make-config Kallithea my.ini
40 paster setup-db my.ini --user=user --email=user@example.com --password=password --repos=/tmp
41 paster serve my.ini --reload &
39 TODO make-config Kallithea my.ini
40 gearbox setup-db -c my.ini --user=user --email=user@example.com --password=password --repos=/tmp
41 gearbox serve -c my.ini --reload &
42 42 firefox http://127.0.0.1:5000/
43 43
44 44 You can also start out by forking https://bitbucket.org/conservancy/kallithea
45 45 on Bitbucket_ and create a local clone of your own fork.
46 46
47 47
48 48 Running tests
49 49 -------------
50 50
51 51 After finishing your changes make sure all tests pass cleanly. Install the test
52 52 dependencies, then run the testsuite by invoking ``py.test`` from the
53 53 project root::
54 54
55 55 pip install -r dev_requirements.txt
56 56 py.test
57 57
58 58 Note that testing on Python 2.6 also requires ``unittest2``.
59 59
60 60 You can also use ``tox`` to run the tests with all supported Python versions
61 61 (currently Python 2.6--2.7).
62 62
63 63 When running tests, Kallithea uses `kallithea/tests/test.ini` and populates the
64 64 SQLite database specified there.
65 65
66 66 It is possible to avoid recreating the full test database on each invocation of
67 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 70 KALLITHEA_WHOOSH_TEST_DISABLE=1 KALLITHEA_NO_TMP_PATH=1 py.test
71 71 kill -9 $(cat test.pid)
72 72
73 73 In these commands, the following variables are used::
74 74
75 75 KALLITHEA_WHOOSH_TEST_DISABLE=1 - skip whoosh index building and tests
76 76 KALLITHEA_NO_TMP_PATH=1 - disable new temp path for tests, used mostly for testing_vcs_operations
77 77
78 78 You can run individual tests by specifying their path as argument to py.test.
79 79 py.test also has many more options, see `py.test -h`. Some useful options
80 80 are::
81 81
82 82 -k EXPRESSION only run tests which match the given substring
83 83 expression. An expression is a python evaluable
84 84 expression where all names are substring-matched
85 85 against test names and their parent classes. Example:
86 86 -x, --exitfirst exit instantly on first error or failed test.
87 87 --lf rerun only the tests that failed at the last run (or
88 88 all if none failed)
89 89 --ff run all tests but run the last failures first. This
90 90 may re-order tests and thus lead to repeated fixture
91 91 setup/teardown
92 92 --pdb start the interactive Python debugger on errors.
93 93 -s, --capture=no don't capture stdout (any stdout output will be
94 94 printed immediately)
95 95
96 96
97 97 Contribution guidelines
98 98 -----------------------
99 99
100 100 Kallithea is GPLv3 and we assume all contributions are made by the
101 101 committer/contributor and under GPLv3 unless explicitly stated. We do care a
102 102 lot about preservation of copyright and license information for existing code
103 103 that is brought into the project.
104 104
105 105 Contributions will be accepted in most formats -- such as pull requests on
106 106 Bitbucket, something hosted on your own Kallithea instance, or patches sent by
107 107 email to the `kallithea-general`_ mailing list.
108 108
109 109 When contributing via Bitbucket, please make your fork of
110 110 https://bitbucket.org/conservancy/kallithea/ `non-publishing`_ -- it is one of
111 111 the settings on "Repository details" page. This ensures your commits are in
112 112 "draft" phase and makes it easier for you to address feedback and for project
113 113 maintainers to integrate your changes.
114 114
115 115 .. _non-publishing: https://www.mercurial-scm.org/wiki/Phases#Publishing_Repository
116 116
117 117 Make sure to test your changes both manually and with the automatic tests
118 118 before posting.
119 119
120 120 We care about quality and review and keeping a clean repository history. We
121 121 might give feedback that requests polishing contributions until they are
122 122 "perfect". We might also rebase and collapse and make minor adjustments to your
123 123 changes when we apply them.
124 124
125 125 We try to make sure we have consensus on the direction the project is taking.
126 126 Everything non-sensitive should be discussed in public -- preferably on the
127 127 mailing list. We aim at having all non-trivial changes reviewed by at least
128 128 one other core developer before pushing. Obvious non-controversial changes will
129 129 be handled more casually.
130 130
131 131 For now we just have one official branch ("default") and will keep it so stable
132 132 that it can be (and is) used in production. Experimental changes should live
133 133 elsewhere (for example in a pull request) until they are ready.
134 134
135 135
136 136 Coding guidelines
137 137 -----------------
138 138
139 139 We don't have a formal coding/formatting standard. We are currently using a mix
140 140 of Mercurial's (https://www.mercurial-scm.org/wiki/CodingStyle), pep8, and
141 141 consistency with existing code. Run ``scripts/run-all-cleanup`` before
142 142 committing to ensure some basic code formatting consistency.
143 143
144 144 We support both Python 2.6.x and 2.7.x and nothing else. For now we don't care
145 145 about Python 3 compatibility.
146 146
147 147 We try to support the most common modern web browsers. IE9 is still supported
148 148 to the extent it is feasible, IE8 is not.
149 149
150 150 We primarily support Linux and OS X on the server side but Windows should also work.
151 151
152 152 HTML templates should use 2 spaces for indentation ... but be pragmatic. We
153 153 should use templates cleverly and avoid duplication. We should use reasonable
154 154 semantic markup with element classes and IDs that can be used for styling and testing.
155 155 We should only use inline styles in places where it really is semantic (such as
156 156 ``display: none``).
157 157
158 158 JavaScript must use ``;`` between/after statements. Indentation 4 spaces. Inline
159 159 multiline functions should be indented two levels -- one for the ``()`` and one for
160 160 ``{}``.
161 161 Variables holding jQuery objects should be named with a leading ``$``.
162 162
163 163 Commit messages should have a leading short line summarizing the changes. For
164 164 bug fixes, put ``(Issue #123)`` at the end of this line.
165 165
166 166 Use American English grammar and spelling overall. Use `English title case`_ for
167 167 page titles, button labels, headers, and 'labels' for fields in forms.
168 168
169 169 .. _English title case: https://en.wikipedia.org/wiki/Capitalization#Title_case
170 170
171 171 Template helpers (that is, everything in ``kallithea.lib.helpers``)
172 172 should only be referenced from templates. If you need to call a
173 173 helper from the Python code, consider moving the function somewhere
174 174 else (e.g. to the model).
175 175
176 176 Notes on the SQLAlchemy session
177 177 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
178 178
179 179 Each HTTP request runs inside an independent SQLAlchemy session (as well
180 180 as in an independent database transaction). Database model objects
181 181 (almost) always belong to a particular SQLAlchemy session, which means
182 182 that SQLAlchemy will ensure that they're kept in sync with the database
183 183 (but also means that they cannot be shared across requests).
184 184
185 185 Objects can be added to the session using ``Session().add``, but this is
186 186 rarely needed:
187 187
188 188 * When creating a database object by calling the constructor directly,
189 189 it must explicitly be added to the session.
190 190
191 191 * When creating an object using a factory function (like
192 192 ``create_repo``), the returned object has already (by convention)
193 193 been added to the session, and should not be added again.
194 194
195 195 * When getting an object from the session (via ``Session().query`` or
196 196 any of the utility functions that look up objects in the database),
197 197 it's already part of the session, and should not be added again.
198 198 SQLAlchemy monitors attribute modifications automatically for all
199 199 objects it knows about and syncs them to the database.
200 200
201 201 SQLAlchemy also flushes changes to the database automatically; manually
202 202 calling ``Session().flush`` is usually only necessary when the Python
203 203 code needs the database to assign an "auto-increment" primary key ID to
204 204 a freshly created model object (before flushing, the ID attribute will
205 205 be ``None``).
206 206
207 207
208 208 "Roadmap"
209 209 ---------
210 210
211 211 We do not have a road map but are waiting for your contributions. Refer to the
212 212 wiki_ for some ideas of places we might want to go -- contributions in these
213 213 areas are very welcome.
214 214
215 215
216 216 Thank you for your contribution!
217 217 --------------------------------
218 218
219 219
220 220 .. _Weblate: http://weblate.org/
221 221 .. _issue tracking: https://bitbucket.org/conservancy/kallithea/issues?status=new&status=open
222 222 .. _pull requests: https://bitbucket.org/conservancy/kallithea/pull-requests
223 223 .. _bitbucket: http://bitbucket.org/
224 224 .. _mailing list: http://lists.sfconservancy.org/mailman/listinfo/kallithea-general
225 225 .. _kallithea-general: http://lists.sfconservancy.org/mailman/listinfo/kallithea-general
226 226 .. _Hosted Weblate: https://hosted.weblate.org/projects/kallithea/kallithea/
227 227 .. _wiki: https://bitbucket.org/conservancy/kallithea/wiki/Home
@@ -1,74 +1,74 b''
1 1 =======================
2 2 Database schema changes
3 3 =======================
4 4
5 5 Kallithea uses Alembic for :ref:`database migrations <upgrade_db>`
6 6 (upgrades and downgrades).
7 7
8 8 If you are developing a Kallithea feature that requires database schema
9 9 changes, you should make a matching Alembic database migration script:
10 10
11 11 1. :ref:`Create a Kallithea configuration and database <setup>` for testing
12 12 the migration script, or use existing ``development.ini`` setup.
13 13
14 14 Ensure that this database is up to date with the latest database
15 15 schema *before* the changes you're currently developing. (Do not
16 16 create the database while your new schema changes are applied.)
17 17
18 18 2. Create a separate throwaway configuration for iterating on the actual
19 19 database changes::
20 20
21 paster make-config Kallithea temp.ini
21 TODO make-config Kallithea temp.ini
22 22
23 23 Edit the file to change database settings. SQLite is typically fine,
24 24 but make sure to change the path to e.g. ``temp.db``, to avoid
25 25 clobbering any existing database file.
26 26
27 27 3. Make your code changes (including database schema changes in ``db.py``).
28 28
29 29 4. After every database schema change, recreate the throwaway database
30 30 to test the changes::
31 31
32 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
34 paster repo-scan temp.ini
33 gearbox setup-db -c temp.ini --repos=/var/repos --user=doe --email doe@example.com --password=123456 --no-public-access --force-yes
34 gearbox repo-scan -c temp.ini
35 35
36 36 5. Once satisfied with the schema changes, auto-generate a draft Alembic
37 37 script using the development database that has *not* been upgraded.
38 38 (The generated script will upgrade the database to match the code.)
39 39
40 40 ::
41 41
42 42 alembic -c development.ini revision -m "area: add cool feature" --autogenerate
43 43
44 44 6. Edit the script to clean it up and fix any problems.
45 45
46 46 Note that for changes that simply add columns, it may be appropriate
47 47 to not remove them in the downgrade script (and instead do nothing),
48 48 to avoid the loss of data. Unknown columns will simply be ignored by
49 49 Kallithea versions predating your changes.
50 50
51 51 7. Run ``alembic -c development.ini upgrade head`` to apply changes to
52 52 the (non-throwaway) database, and test the upgrade script. Also test
53 53 downgrades.
54 54
55 55 The included ``development.ini`` has full SQL logging enabled. If
56 56 you're using another configuration file, you may want to enable it
57 57 by setting ``level = DEBUG`` in section ``[handler_console_sql]``.
58 58
59 59 The Alembic migration script should be committed in the same revision as
60 60 the database schema (``db.py``) changes.
61 61
62 62 See the `Alembic documentation`__ for more information, in particular
63 63 the tutorial and the section about auto-generating migration scripts.
64 64
65 65 .. __: http://alembic.zzzcomputing.com/en/latest/
66 66
67 67
68 68 Troubleshooting
69 69 ---------------
70 70
71 71 * If ``alembic --autogenerate`` responds "Target database is not up to
72 72 date", you need to either first use Alembic to upgrade the database
73 73 to the most recent version (before your changes), or recreate the
74 74 database from scratch (without your schema changes applied).
@@ -1,129 +1,129 b''
1 1 .. _installation_iis:
2 2
3 3 =====================================================================
4 4 Installing Kallithea on Microsoft Internet Information Services (IIS)
5 5 =====================================================================
6 6
7 7 The following is documented using IIS 7/8 terminology. There should be nothing
8 8 preventing you from applying this on IIS 6 well.
9 9
10 10 .. note::
11 11
12 12 Installing Kallithea under IIS can enable Single Sign-On to the Kallithea
13 13 web interface from web browsers that can authenticate to the web server.
14 14 (As an alternative to IIS, SSO is also possible with for example Apache and
15 15 mod_sspi.)
16 16
17 17 Mercurial and Git do however by default not support SSO on the client side
18 18 and will still require some other kind of authentication.
19 19 (An extension like hgssoauthentication_ might solve that.)
20 20
21 21 .. note::
22 22
23 23 For the best security, it is strongly recommended to only host the site over
24 24 a secure connection, e.g. using TLS.
25 25
26 26
27 27 Prerequisites
28 28 -------------
29 29
30 30 Apart from the normal requirements for Kallithea, it is also necessary to get an
31 31 ISAPI-WSGI bridge module, e.g. isapi-wsgi.
32 32
33 33
34 34 Installation
35 35 ------------
36 36
37 37 The following assumes that your Kallithea is at ``c:\inetpub\kallithea``, and
38 38 will be served from the root of its own website. The changes to serve it in its
39 39 own virtual folder will be noted where appropriate.
40 40
41 41 Application pool
42 42 ^^^^^^^^^^^^^^^^
43 43
44 44 Make sure that there is a unique application pool for the Kallithea application
45 45 with an identity that has read access to the Kallithea distribution.
46 46
47 47 The application pool does not need to be able to run any managed code. If you
48 48 are using a 32-bit Python installation, then you must enable 32-bit program in
49 49 the advanced settings for the application pool; otherwise Python will not be able
50 50 to run on the website and neither will Kallithea.
51 51
52 52 .. note::
53 53
54 54 The application pool can be the same as an existing application pool,
55 55 as long as the Kallithea requirements are met by the existing pool.
56 56
57 57 ISAPI handler
58 58 ^^^^^^^^^^^^^
59 59
60 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 64 This will generate a ``dispatch.py`` file in the current directory that contains
65 65 the necessary components to finalize an installation into IIS. Once this file
66 66 has been generated, it is necessary to run the following command due to the way
67 67 that ISAPI-WSGI is made::
68 68
69 69 python2 dispatch.py install
70 70
71 71 This accomplishes two things: generating an ISAPI compliant DLL file,
72 72 ``_dispatch.dll``, and installing a script map handler into IIS for the
73 73 ``--virtualdir`` specified above pointing to ``_dispatch.dll``.
74 74
75 75 The ISAPI handler is registered to all file extensions, so it will automatically
76 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 78 middleware WSGI handler that Kallithea runs within and each HTTP request to the
79 79 site will be processed through this logic henceforth.
80 80
81 81 Authentication with Kallithea using IIS authentication modules
82 82 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
83 83
84 84 The recommended way to handle authentication with Kallithea using IIS is to let
85 85 IIS handle all the authentication and just pass it to Kallithea.
86 86
87 87 .. note::
88 88
89 89 As an alternative without SSO, you can also use LDAP authentication with
90 90 Active Directory, see :ref:`ldap-setup`.
91 91
92 92 To move responsibility into IIS from Kallithea, we need to configure Kallithea
93 93 to let external systems handle authentication and then let Kallithea create the
94 94 user automatically. To do this, access the administration's authentication page
95 95 and enable the ``kallithea.lib.auth_modules.auth_container`` plugin. Once it is
96 96 added, enable it with the ``REMOTE_USER`` header and check *Clean username*.
97 97 Finally, save the changes on this page.
98 98
99 99 Switch to the administration's permissions page and disable anonymous access,
100 100 otherwise Kallithea will not attempt to use the authenticated user name. By
101 101 default, Kallithea will populate the list of users lazily as they log in. Either
102 102 disable external auth account activation and ensure that you pre-populate the
103 103 user database with an external tool, or set it to *Automatic activation of
104 104 external account*. Finally, save the changes.
105 105
106 106 The last necessary step is to enable the relevant authentication in IIS, e.g.
107 107 Windows authentication.
108 108
109 109
110 110 Troubleshooting
111 111 ---------------
112 112
113 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 115 different options for finding issues exist: IIS' failed request tracking which
116 116 is great at finding issues until they exist inside Kallithea, at which point the
117 117 ISAPI-WSGI wrapper above uses ``win32traceutil``, which is part of ``pywin32``.
118 118
119 119 In order to dump output from WSGI using ``win32traceutil`` it is sufficient to
120 120 type the following in a console window::
121 121
122 122 python2 -m win32traceutil
123 123
124 124 and any exceptions occurring in the WSGI layer and below (i.e. in the Kallithea
125 125 application itself) that are uncaught, will be printed here complete with stack
126 126 traces, making it a lot easier to identify issues.
127 127
128 128
129 129 .. _hgssoauthentication: https://bitbucket.org/domruf/hgssoauthentication
@@ -1,223 +1,223 b''
1 1 .. _installation_win:
2 2
3 3 ====================================================
4 4 Installation on Windows (7/Server 2008 R2 and newer)
5 5 ====================================================
6 6
7 7
8 8 First time install
9 9 ------------------
10 10
11 11 Target OS: Windows 7 and newer or Windows Server 2008 R2 and newer
12 12
13 13 Tested on Windows 8.1, Windows Server 2008 R2 and Windows Server 2012
14 14
15 15 To install on an older version of Windows, see `<installation_win_old.html>`_
16 16
17 17 Step 1 -- Install Python
18 18 ^^^^^^^^^^^^^^^^^^^^^^^^
19 19
20 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 22 .. warning:: Python 3.x is not supported.
23 23
24 24 - Download Python 2.x.y from http://www.python.org/download/
25 25 - Choose and click on the version
26 26 - Click on "Windows X86-64 Installer" for x64 or "Windows x86 MSI installer" for Win32.
27 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 29 While writing this guide, the latest version was v2.7.9.
30 30 Remember the specific major and minor versions installed, because they will
31 31 be needed in the next step. In this case, it is "2.7".
32 32
33 33 Step 2 -- Python BIN
34 34 ^^^^^^^^^^^^^^^^^^^^
35 35
36 36 Add Python BIN folder to the path. This can be done manually (editing
37 37 "PATH" environment variable) or by using Windows Support Tools that
38 38 come pre-installed in Windows Vista/7 and later.
39 39
40 40 Open a CMD and type::
41 41
42 42 SETX PATH "%PATH%;[your-python-path]" /M
43 43
44 44 Please substitute [your-python-path] with your Python installation
45 45 path. Typically this is ``C:\\Python27``.
46 46
47 47 Step 3 -- Install pywin32 extensions
48 48 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
49 49
50 50 Download pywin32 from:
51 51 http://sourceforge.net/projects/pywin32/files/
52 52
53 53 - Click on "pywin32" folder
54 54 - Click on the first folder (in this case, Build 219, maybe newer when you try)
55 55 - Choose the file ending with ".amd64-py2.x.exe" (".win32-py2.x.exe"
56 56 for Win32) where x is the minor version of Python you installed.
57 57 When writing this guide, the file was:
58 58 http://sourceforge.net/projects/pywin32/files/pywin32/Build%20219/pywin32-219.win-amd64-py2.7.exe/download
59 59 (x64)
60 60 http://sourceforge.net/projects/pywin32/files/pywin32/Build%20219/pywin32-219.win32-py2.7.exe/download
61 61 (Win32)
62 62
63 63 Step 4 -- Install pip
64 64 ^^^^^^^^^^^^^^^^^^^^^
65 65
66 66 pip is a package management system for Python. You will need it to install Kallithea and its dependencies.
67 67
68 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 70 If it was not installed or if you are using Python>=2.6,<2.7.9:
71 71
72 72 - Go to https://bootstrap.pypa.io
73 73 - Right-click on get-pip.py and choose Saves as...
74 74 - Run "python2 get-pip.py" in the folder where you downloaded get-pip.py (may require admin access).
75 75
76 76 .. note::
77 77
78 78 See http://stackoverflow.com/questions/4750806/how-to-install-pip-on-windows
79 79 for details and alternative methods.
80 80
81 81 Note that pip.exe will be placed inside your Python installation's
82 82 Scripts folder, which is likely not on your path. To correct this,
83 83 open a CMD and type::
84 84
85 85 SETX PATH "%PATH%;[your-python-path]\Scripts" /M
86 86
87 87 Step 5 -- Kallithea folder structure
88 88 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
89 89
90 90 Create a Kallithea folder structure.
91 91
92 92 This is only an example to install Kallithea. Of course, you can
93 93 change it. However, this guide will follow the proposed structure, so
94 94 please later adapt the paths if you change them. Folders without
95 95 spaces are recommended.
96 96
97 97 Create the following folder structure::
98 98
99 99 C:\Kallithea
100 100 C:\Kallithea\Bin
101 101 C:\Kallithea\Env
102 102 C:\Kallithea\Repos
103 103
104 104 Step 6 -- Install virtualenv
105 105 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
106 106
107 107 .. note::
108 108 A python virtual environment will allow for isolation between the Python packages of your system and those used for Kallithea.
109 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 111 In a command prompt type::
112 112
113 113 pip install virtualenv
114 114
115 115 Virtualenv will now be inside your Python Scripts path (C:\\Python27\\Scripts or similar).
116 116
117 117 To create a virtual environment, run::
118 118
119 119 virtualenv C:\Kallithea\Env
120 120
121 121 Step 7 -- Install Kallithea
122 122 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
123 123
124 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 125 Some Python packages use managed code and need to be compiled.
126 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 128 Download and install "Microsoft Visual C++ Compiler for Python 2.7" from http://aka.ms/vcpython27
129 129
130 130 .. note::
131 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 133 In a command prompt type (adapting paths if necessary)::
134 134
135 135 cd C:\Kallithea\Env\Scripts
136 136 activate
137 137 pip install --upgrade pip setuptools
138 138
139 139 The prompt will change into "(Env) C:\\Kallithea\\Env\\Scripts" or similar
140 140 (depending of your folder structure). Then type::
141 141
142 142 pip install kallithea
143 143
144 144 .. note:: This will take some time. Please wait patiently until it is fully
145 145 complete. Some warnings will appear. Don't worry, they are
146 146 normal.
147 147
148 148 Step 8 -- Install Git (optional)
149 149 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
150 150
151 151 Mercurial being a python package, was installed automatically when doing ``pip install kallithea``.
152 152
153 153 You need to install Git manually if you want Kallithea to be able to host Git repositories.
154 154 See http://git-scm.com/book/en/v2/Getting-Started-Installing-Git#Installing-on-Windows for instructions.
155 155 The location of the Git binaries (like ``c:\path\to\git\bin``) must be
156 156 added to the ``PATH`` environment variable so ``git.exe`` and other tools like
157 157 ``gzip.exe`` are available.
158 158
159 159 Step 9 -- Configuring Kallithea
160 160 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
161 161
162 162 Steps taken from `<setup.html>`_
163 163
164 164 You have to use the same command prompt as in Step 7, so if you closed
165 165 it, reopen it following the same commands (including the "activate"
166 166 one). When ready, type::
167 167
168 168 cd C:\Kallithea\Bin
169 paster make-config Kallithea production.ini
169 TODO make-config Kallithea production.ini
170 170
171 171 Then you must edit production.ini to fit your needs (IP address, IP
172 172 port, mail settings, database, etc.). `NotePad++`__ or a similar text
173 173 editor is recommended to properly handle the newline character
174 174 differences between Unix and Windows.
175 175
176 176 __ http://notepad-plus-plus.org/
177 177
178 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 182 .. warning:: This time a *new* database will be installed. You must
183 183 follow a different process to later :ref:`upgrade <upgrade>`
184 184 to a newer Kallithea version.
185 185
186 186 The script will ask you for confirmation about creating a new database, answer yes (y)
187 187
188 188 The script will ask you for the repository path, answer C:\\Kallithea\\Repos (or similar).
189 189
190 190 The script will ask you for the admin username and password, answer "admin" + "123456" (or whatever you want)
191 191
192 192 The script will ask you for admin mail, answer "admin@xxxx.com" (or whatever you want).
193 193
194 194 If you make a mistake and the script doesn't end, don't worry: start it again.
195 195
196 196 If you decided not to install Git, you will get errors about it that you can ignore.
197 197
198 198 Step 10 -- Running Kallithea
199 199 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
200 200
201 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 205 Open your web server, and go to http://127.0.0.1:5000
206 206
207 207 It works!! :-)
208 208
209 209 Remark:
210 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 212 What this guide does not cover:
213 213
214 214 - Installing Celery
215 215 - Running Kallithea as a Windows Service. You can investigate here:
216 216
217 217 - http://pypi.python.org/pypi/wsgisvc
218 218 - http://ryrobes.com/python/running-python-scripts-as-a-windows-service/
219 219 - http://wiki.pylonshq.com/display/pylonscookbook/How+to+run+Pylons+as+a+Windows+service
220 220
221 221 - Using Apache. You can investigate here:
222 222
223 223 - https://groups.google.com/group/rhodecode/msg/c433074e813ffdc4
@@ -1,263 +1,263 b''
1 1 .. _installation_win_old:
2 2
3 3 ==========================================================
4 4 Installation on Windows (XP/Vista/Server 2003/Server 2008)
5 5 ==========================================================
6 6
7 7
8 8 First-time install
9 9 ------------------
10 10
11 11 Target OS: Windows XP SP3 32-bit English (Clean installation)
12 12 + All Windows Updates until 24-may-2012
13 13
14 14 .. note::
15 15
16 16 This installation is for 32-bit systems, for 64-bit Windows you might need
17 17 to download proper 64-bit versions of the different packages (Windows Installer, Win32py extensions)
18 18 plus some extra tweaks.
19 19 These extra steps haven been marked as "64-bit".
20 20 Tested on Windows Server 2008 R2 SP1, 9-feb-2013.
21 21 If you run into any 64-bit related problems, please check these pages:
22 22
23 23 - http://blog.victorjabur.com/2011/06/05/compiling-python-2-7-modules-on-windows-32-and-64-using-msvc-2008-express/
24 24 - http://bugs.python.org/issue7511
25 25
26 26 Step 1 -- Install Visual Studio 2008 Express
27 27 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
28 28
29 29 Optional: You can also install MinGW, but VS2008 installation is easier.
30 30
31 31 Download "Visual C++ 2008 Express Edition with SP1" from:
32 32 http://download.microsoft.com/download/E/8/E/E8EEB394-7F42-4963-A2D8-29559B738298/VS2008ExpressWithSP1ENUX1504728.iso
33 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 35 You can also download full ISO file for offline installation, just
36 36 choose "All -- Offline Install ISO image file" in the previous page and
37 37 choose "Visual C++ 2008 Express" when installing.
38 38
39 39 .. note::
40 40
41 41 Using other versions of Visual Studio will lead to random crashes.
42 42 You must use Visual Studio 2008!"
43 43
44 44 .. note::
45 45
46 46 Silverlight Runtime and SQL Server 2008 Express Edition are not
47 47 required, you can uncheck them
48 48
49 49 .. note::
50 50
51 51 64-bit: You also need to install the Microsoft Windows SDK for .NET 3.5 SP1 (.NET 4.0 won't work).
52 52 Download from: http://www.microsoft.com/en-us/download/details.aspx?id=3138
53 53
54 54 .. note::
55 55
56 56 64-bit: You also need to copy and rename a .bat file to make the Visual C++ compiler work.
57 57 I am not sure why this is not necessary for 32-bit.
58 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 60 Step 2 -- Install Python
61 61 ^^^^^^^^^^^^^^^^^^^^^^^^
62 62
63 63 Install Python 2.x.y (x = 6 or 7) x86 version (32-bit). DO NOT USE A 3.x version.
64 64 Download Python 2.x.y from:
65 65 http://www.python.org/download/
66 66
67 67 Choose "Windows Installer" (32-bit version) not "Windows X86-64
68 68 Installer". While writing this guide, the latest version was v2.7.3.
69 69 Remember the specific major and minor version installed, because it will
70 70 be needed in the next step. In this case, it is "2.7".
71 71
72 72 .. note::
73 73
74 74 64-bit: Just download and install the 64-bit version of python.
75 75
76 76 Step 3 -- Install Win32py extensions
77 77 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
78 78
79 79 Download pywin32 from:
80 80 http://sourceforge.net/projects/pywin32/files/
81 81
82 82 - Click on "pywin32" folder
83 83 - Click on the first folder (in this case, Build 217, maybe newer when you try)
84 84 - Choose the file ending with ".win32-py2.x.exe" -> x being the minor
85 85 version of Python you installed (in this case, 7)
86 86 When writing this guide, the file was:
87 87 http://sourceforge.net/projects/pywin32/files/pywin32/Build%20217/pywin32-217.win32-py2.7.exe/download
88 88
89 89 .. note::
90 90
91 91 64-bit: Download and install the 64-bit version.
92 92 At the time of writing you can find this at:
93 93 http://sourceforge.net/projects/pywin32/files/pywin32/Build%20218/pywin32-218.win-amd64-py2.7.exe/download
94 94
95 95 Step 4 -- Python BIN
96 96 ^^^^^^^^^^^^^^^^^^^^
97 97
98 98 Add Python BIN folder to the path
99 99
100 100 You have to add the Python folder to the path, you can do it manually
101 101 (editing "PATH" environment variable) or using Windows Support Tools
102 102 that came preinstalled in Vista/7 and can be installed in Windows XP.
103 103
104 104 - Using support tools on WINDOWS XP:
105 105 If you use Windows XP you can install them using Windows XP CD and
106 106 navigating to \SUPPORT\TOOLS. There, execute Setup.EXE (not MSI).
107 107 Afterwards, open a CMD and type::
108 108
109 109 SETX PATH "%PATH%;[your-python-path]" -M
110 110
111 111 Close CMD (the path variable will be updated then)
112 112
113 113 - Using support tools on WINDOWS Vista/7:
114 114
115 115 Open a CMD and type::
116 116
117 117 SETX PATH "%PATH%;[your-python-path]" /M
118 118
119 119 Please substitute [your-python-path] with your Python installation path.
120 120 Typically: C:\\Python27
121 121
122 122 Step 5 -- Kallithea folder structure
123 123 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
124 124
125 125 Create a Kallithea folder structure
126 126
127 127 This is only a example to install Kallithea, you can of course change
128 128 it. However, this guide will follow the proposed structure, so please
129 129 later adapt the paths if you change them. My recommendation is to use
130 130 folders with NO SPACES. But you can try if you are brave...
131 131
132 132 Create the following folder structure::
133 133
134 134 C:\Kallithea
135 135 C:\Kallithea\Bin
136 136 C:\Kallithea\Env
137 137 C:\Kallithea\Repos
138 138
139 139 Step 6 -- Install virtualenv
140 140 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
141 141
142 142 Install Virtual Env for Python
143 143
144 144 Navigate to: http://www.virtualenv.org/en/latest/index.html#installation
145 145 Right click on "virtualenv.py" file and choose "Save link as...".
146 146 Download to C:\\Kallithea (or whatever you want)
147 147 (the file is located at
148 148 https://raw.github.com/pypa/virtualenv/master/virtualenv.py)
149 149
150 150 Create a virtual Python environment in C:\\Kallithea\\Env (or similar). To
151 151 do so, open a CMD (Python Path should be included in Step3), navigate
152 152 where you downloaded "virtualenv.py", and write::
153 153
154 154 python2 virtualenv.py C:\Kallithea\Env
155 155
156 156 (--no-site-packages is now the default behaviour of virtualenv, no need
157 157 to include it)
158 158
159 159 Step 7 -- Install Kallithea
160 160 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
161 161
162 162 Finally, install Kallithea
163 163
164 164 Close previously opened command prompt/s, and open a Visual Studio 2008
165 165 Command Prompt (**IMPORTANT!!**). To do so, go to Start Menu, and then open
166 166 "Microsoft Visual C++ 2008 Express Edition" -> "Visual Studio Tools" ->
167 167 "Visual Studio 2008 Command Prompt"
168 168
169 169 .. note::
170 170
171 171 64-bit: For 64-bit you need to modify the shortcut that is used to start the
172 172 Visual Studio 2008 Command Prompt. Use right-mouse click to open properties.
173 173
174 174 Change commandline from::
175 175
176 176 %comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"" x86
177 177
178 178 to::
179 179
180 180 %comspec% /k ""C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"" amd64
181 181
182 182 In that CMD (loaded with VS2008 PATHs) type::
183 183
184 184 cd C:\Kallithea\Env\Scripts (or similar)
185 185 activate
186 186 pip install --upgrade pip setuptools
187 187
188 188 The prompt will change into "(Env) C:\\Kallithea\\Env\\Scripts" or similar
189 189 (depending of your folder structure). Then type::
190 190
191 191 pip install kallithea
192 192
193 193 (long step, please wait until fully complete)
194 194
195 195 Some warnings will appear, don't worry as they are normal.
196 196
197 197 Step 8 -- Configuring Kallithea
198 198 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
199 199
200 200 steps taken from http://packages.python.org/Kallithea/setup.html
201 201
202 202 You have to use the same Visual Studio 2008 command prompt as Step7, so
203 203 if you closed it reopen it following the same commands (including the
204 204 "activate" one). When ready, just type::
205 205
206 206 cd C:\Kallithea\Bin
207 paster make-config Kallithea production.ini
207 TODO make-config Kallithea production.ini
208 208
209 209 Then, you must edit production.ini to fit your needs (network address and
210 210 port, mail settings, database, whatever). I recommend using NotePad++
211 211 (free) or similar text editor, as it handles well the EndOfLine
212 212 character differences between Unix and Windows
213 213 (http://notepad-plus-plus.org/)
214 214
215 215 For the sake of simplicity lets run it with the default settings. After
216 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 220 .. warning:: This time a *new* database will be installed. You must
221 221 follow a different process to later :ref:`upgrade <upgrade>`
222 222 to a newer Kallithea version.
223 223
224 224 The script will ask you for confirmation about creating a NEW database,
225 225 answer yes (y)
226 226 The script will ask you for repository path, answer C:\\Kallithea\\Repos
227 227 (or similar)
228 228 The script will ask you for admin username and password, answer "admin"
229 229 + "123456" (or whatever you want)
230 230 The script will ask you for admin mail, answer "admin@xxxx.com" (or
231 231 whatever you want)
232 232
233 233 If you make some mistake and the script does not end, don't worry, start
234 234 it again.
235 235
236 236 Step 9 -- Running Kallithea
237 237 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
238 238
239 239 In the previous command prompt, being in the C:\\Kallithea\\Bin folder,
240 240 just type::
241 241
242 paster serve production.ini
242 gearbox serve -c production.ini
243 243
244 244 Open yout web server, and go to http://127.0.0.1:5000
245 245
246 246 It works!! :-)
247 247
248 248 Remark:
249 249 If it does not work first time, just Ctrl-C the CMD process and start it
250 250 again. Don't forget the "http://" in Internet Explorer
251 251
252 252 What this Guide does not cover:
253 253
254 254 - Installing Celery
255 255 - Running Kallithea as Windows Service. You can investigate here:
256 256
257 257 - http://pypi.python.org/pypi/wsgisvc
258 258 - http://ryrobes.com/python/running-python-scripts-as-a-windows-service/
259 259 - http://wiki.pylonshq.com/display/pylonscookbook/How+to+run+Pylons+as+a+Windows+service
260 260
261 261 - Using Apache. You can investigate here:
262 262
263 263 - https://groups.google.com/group/rhodecode/msg/c433074e813ffdc4
@@ -1,140 +1,140 b''
1 1 .. _overview:
2 2
3 3 =====================
4 4 Installation overview
5 5 =====================
6 6
7 7 Some overview and some details that can help understanding the options when
8 8 installing Kallithea.
9 9
10 10
11 11 Python environment
12 12 ------------------
13 13
14 14 **Kallithea** is written entirely in Python_ and requires Python version
15 15 2.6 or higher. Python 3.x is currently not supported.
16 16
17 17 Given a Python installation, there are different ways of providing the
18 18 environment for running Python applications. Each of them pretty much
19 19 corresponds to a ``site-packages`` directory somewhere where packages can be
20 20 installed.
21 21
22 22 Kallithea itself can be run from source or be installed, but even when running
23 23 from source, there are some dependencies that must be installed in the Python
24 24 environment used for running Kallithea.
25 25
26 26 - Packages *could* be installed in Python's ``site-packages`` directory ... but
27 27 that would require running pip_ as root and it would be hard to uninstall or
28 28 upgrade and is probably not a good idea unless using a package manager.
29 29
30 30 - Packages could also be installed in ``~/.local`` ... but that is probably
31 31 only a good idea if using a dedicated user per application or instance.
32 32
33 33 - Finally, it can be installed in a virtualenv_. That is a very lightweight
34 34 "container" where each Kallithea instance can get its own dedicated and
35 35 self-contained virtual environment.
36 36
37 37 We recommend using virtualenv for installing Kallithea.
38 38
39 39
40 40 Installation methods
41 41 --------------------
42 42
43 43 Kallithea must be installed on a server. Kallithea is installed in a Python
44 44 environment so it can use packages that are installed there and make itself
45 45 available for other packages.
46 46
47 47 Two different cases will pretty much cover the options for how it can be
48 48 installed.
49 49
50 50 - The Kallithea source repository can be cloned and used -- it is kept stable and
51 51 can be used in production. The Kallithea maintainers use the development
52 52 branch in production. The advantage of installation from source and regularly
53 53 updating it is that you take advantage of the most recent improvements. Using
54 54 it directly from a DVCS also means that it is easy to track local customizations.
55 55
56 56 Running ``pip install -e .`` in the source will use pip to install the
57 57 necessary dependencies in the Python environment and create a
58 58 ``.../site-packages/Kallithea.egg-link`` file there that points at the Kallithea
59 59 source.
60 60
61 61 - Kallithea can also be installed from ready-made packages using a package manager.
62 62 The official released versions are available on PyPI_ and can be downloaded and
63 63 installed with all dependencies using ``pip install kallithea``.
64 64
65 65 With this method, Kallithea is installed in the Python environment as any
66 66 other package, usually as a ``.../site-packages/Kallithea-X-py2.7.egg/``
67 67 directory with Python files and everything else that is needed.
68 68
69 69 (``pip install kallithea`` from a source tree will do pretty much the same
70 70 but build the Kallithea package itself locally instead of downloading it.)
71 71
72 72
73 73 Web server
74 74 ----------
75 75
76 76 Kallithea is (primarily) a WSGI_ application that must be run from a web
77 77 server that serves WSGI applications over HTTP.
78 78
79 79 Kallithea itself is not serving HTTP (or HTTPS); that is the web server's
80 80 responsibility. Kallithea does however need to know its own user facing URL
81 81 (protocol, address, port and path) for each HTTP request. Kallithea will
82 82 usually use its own HTML/cookie based authentication but can also be configured
83 83 to use web server authentication.
84 84
85 85 There are several web server options:
86 86
87 - Kallithea uses the Paste_ tool as command line interface. Paste provides
88 ``paster serve`` as a convenient way to launch a Python WSGI / web server
87 - Kallithea uses the Gearbox_ tool as command line interface. Gearbox provides
88 ``gearbox serve`` as a convenient way to launch a Python WSGI / web server
89 89 from the command line. That is perfect for development and evaluation.
90 90 Actual use in production might have different requirements and need extra
91 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 94 Waitress_. Gunicorn_ is also an option. These web servers have different
95 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 98 to it. The entry point for the WSGI application is configured
99 99 in ``setup.py`` as ``kallithea.config.middleware:make_app``.
100 100
101 101 - `Apache httpd`_ can serve WSGI applications directly using mod_wsgi_ and a
102 102 simple Python file with the necessary configuration. This is a good option if
103 103 Apache is an option.
104 104
105 105 - uWSGI_ is also a full web server with built-in WSGI module.
106 106
107 107 - IIS_ can also server WSGI applications directly using isapi-wsgi_.
108 108
109 109 - A `reverse HTTP proxy <https://en.wikipedia.org/wiki/Reverse_proxy>`_
110 110 can be put in front of another web server which has WSGI support.
111 111 Such a layered setup can be complex but might in some cases be the right
112 112 option, for example to standardize on one internet-facing web server, to add
113 113 encryption or special authentication or for other security reasons, to
114 114 provide caching of static files, or to provide load balancing or fail-over.
115 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 118 The best option depends on what you are familiar with and the requirements for
119 119 performance and stability. Also, keep in mind that Kallithea mainly is serving
120 120 dynamically generated pages from a relatively slow Python process. Kallithea is
121 121 also often used inside organizations with a limited amount of users and thus no
122 122 continuous hammering from the internet.
123 123
124 124
125 125 .. _Python: http://www.python.org/
126 126 .. _Gunicorn: http://gunicorn.org/
127 127 .. _Waitress: http://waitress.readthedocs.org/en/latest/
128 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 130 .. _PyPI: https://pypi.python.org/pypi
131 131 .. _Apache httpd: http://httpd.apache.org/
132 132 .. _mod_wsgi: https://code.google.com/p/modwsgi/
133 133 .. _isapi-wsgi: https://github.com/hexdump42/isapi-wsgi
134 134 .. _uWSGI: https://uwsgi-docs.readthedocs.org/en/latest/
135 135 .. _nginx: http://nginx.org/en/
136 136 .. _iis: http://en.wikipedia.org/wiki/Internet_Information_Services
137 137 .. _pip: http://en.wikipedia.org/wiki/Pip_%28package_manager%29
138 138 .. _WSGI: http://en.wikipedia.org/wiki/Web_Server_Gateway_Interface
139 139 .. _HAProxy: http://www.haproxy.org/
140 140 .. _Varnish: https://www.varnish-cache.org/
@@ -1,874 +1,877 b''
1 1 .. _setup:
2 2
3 3 =====
4 4 Setup
5 5 =====
6 6
7 7
8 8 Setting up Kallithea
9 9 --------------------
10 10
11 11 First, you will need to create a Kallithea configuration file. Run the
12 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 16 This will create the file ``my.ini`` in the current directory. This
17 17 configuration file contains the various settings for Kallithea, e.g.
18 18 proxy port, email settings, usage of static files, cache, Celery
19 19 settings, and logging.
20 20
21 21 Next, you need to create the databases used by Kallithea. It is recommended to
22 22 use PostgreSQL or SQLite (default). If you choose a database other than the
23 23 default, ensure you properly adjust the database URL in your ``my.ini``
24 24 configuration file to use this other database. Kallithea currently supports
25 25 PostgreSQL, SQLite and MySQL databases. Create the database by running
26 26 the following command::
27 27
28 paster setup-db my.ini
28 gearbox setup-db -c my.ini
29 29
30 30 This will prompt you for a "root" path. This "root" path is the location where
31 31 Kallithea will store all of its repositories on the current machine. After
32 32 entering this "root" path ``setup-db`` will also prompt you for a username
33 33 and password for the initial admin account which ``setup-db`` sets
34 34 up for you.
35 35
36 36 The ``setup-db`` values can also be given on the command line.
37 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 41 The ``setup-db`` command will create all needed tables and an
42 42 admin account. When choosing a root path you can either use a new
43 43 empty location, or a location which already contains existing
44 44 repositories. If you choose a location which contains existing
45 45 repositories Kallithea will add all of the repositories at the chosen
46 46 location to its database. (Note: make sure you specify the correct
47 47 path to the root).
48 48
49 49 .. note:: the given path for Mercurial_ repositories **must** be write
50 50 accessible for the application. It's very important since
51 51 the Kallithea web interface will work without write access,
52 52 but when trying to do a push it will fail with permission
53 53 denied errors unless it has write access.
54 54
55 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 59 - This command runs the Kallithea server. The web app should be available at
60 60 http://127.0.0.1:5000. The IP address and port is configurable via the
61 61 configuration file created in the previous step.
62 62 - Log in to Kallithea using the admin account created when running ``setup-db``.
63 63 - The default permissions on each repository is read, and the owner is admin.
64 64 Remember to update these if needed.
65 65 - In the admin panel you can toggle LDAP, anonymous, and permissions
66 66 settings, as well as edit more advanced options on users and
67 67 repositories.
68 68
69 69
70 70 Using Kallithea with SSH
71 71 ------------------------
72 72
73 73 Kallithea currently only hosts repositories using http and https. (The addition
74 74 of ssh hosting is a planned future feature.) However you can easily use ssh in
75 75 parallel with Kallithea. (Repository access via ssh is a standard "out of
76 76 the box" feature of Mercurial_ and you can use this to access any of the
77 77 repositories that Kallithea is hosting. See PublishingRepositories_)
78 78
79 79 Kallithea repository structures are kept in directories with the same name
80 80 as the project. When using repository groups, each group is a subdirectory.
81 81 This allows you to easily use ssh for accessing repositories.
82 82
83 83 In order to use ssh you need to make sure that your web server and the users'
84 84 login accounts have the correct permissions set on the appropriate directories.
85 85
86 86 .. note:: These permissions are independent of any permissions you
87 87 have set up using the Kallithea web interface.
88 88
89 89 If your main directory (the same as set in Kallithea settings) is for
90 90 example set to ``/srv/repos`` and the repository you are using is
91 91 named ``kallithea``, then to clone via ssh you should run::
92 92
93 93 hg clone ssh://user@kallithea.example.com/srv/repos/kallithea
94 94
95 95 Using other external tools such as mercurial-server_ or using ssh key-based
96 96 authentication is fully supported.
97 97
98 98 .. note:: In an advanced setup, in order for your ssh access to use
99 99 the same permissions as set up via the Kallithea web
100 100 interface, you can create an authentication hook to connect
101 101 to the Kallithea db and run check functions for permissions
102 102 against that.
103 103
104 104
105 105 Setting up Whoosh full text search
106 106 ----------------------------------
107 107
108 108 Kallithea provides full text search of repositories using `Whoosh`__.
109 109
110 110 .. __: https://pythonhosted.org/Whoosh/
111 111
112 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 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 120 The ``--repo-location`` option allows the location of the repositories to be overridden;
121 121 usually, the location is retrieved from the Kallithea database.
122 122
123 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 127 To keep your index up-to-date it is necessary to do periodic index builds;
128 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 132 When using incremental mode (the default), Whoosh will check the last
133 133 modification date of each file and add it to be reindexed if a newer file is
134 134 available. The indexing daemon checks for any removed files and removes them
135 135 from index.
136 136
137 137 If you want to rebuild the index from scratch, you can use the ``-f`` flag as above,
138 138 or in the admin panel you can check the "build from scratch" checkbox.
139 139
140 140 .. _ldap-setup:
141 141
142 142
143 143 Setting up LDAP support
144 144 -----------------------
145 145
146 146 Kallithea supports LDAP authentication. In order
147 147 to use LDAP, you have to install the python-ldap_ package. This package is
148 148 available via PyPI, so you can install it by running::
149 149
150 150 pip install python-ldap
151 151
152 152 .. note:: ``python-ldap`` requires some libraries to be installed on
153 153 your system, so before installing it check that you have at
154 154 least the ``openldap`` and ``sasl`` libraries.
155 155
156 156 Choose *Admin > Authentication*, click the ``kallithea.lib.auth_modules.auth_ldap`` button
157 157 and then *Save*, to enable the LDAP plugin and configure its settings.
158 158
159 159 Here's a typical LDAP setup::
160 160
161 161 Connection settings
162 162 Enable LDAP = checked
163 163 Host = host.example.com
164 164 Account = <account>
165 165 Password = <password>
166 166 Connection Security = LDAPS
167 167 Certificate Checks = DEMAND
168 168
169 169 Search settings
170 170 Base DN = CN=users,DC=host,DC=example,DC=org
171 171 LDAP Filter = (&(objectClass=user)(!(objectClass=computer)))
172 172 LDAP Search Scope = SUBTREE
173 173
174 174 Attribute mappings
175 175 Login Attribute = uid
176 176 First Name Attribute = firstName
177 177 Last Name Attribute = lastName
178 178 Email Attribute = mail
179 179
180 180 If your user groups are placed in an Organisation Unit (OU) structure, the Search Settings configuration differs::
181 181
182 182 Search settings
183 183 Base DN = DC=host,DC=example,DC=org
184 184 LDAP Filter = (&(memberOf=CN=your user group,OU=subunit,OU=unit,DC=host,DC=example,DC=org)(objectClass=user))
185 185 LDAP Search Scope = SUBTREE
186 186
187 187 .. _enable_ldap:
188 188
189 189 Enable LDAP : required
190 190 Whether to use LDAP for authenticating users.
191 191
192 192 .. _ldap_host:
193 193
194 194 Host : required
195 195 LDAP server hostname or IP address. Can be also a comma separated
196 196 list of servers to support LDAP fail-over.
197 197
198 198 .. _Port:
199 199
200 200 Port : optional
201 201 Defaults to 389 for PLAIN un-encrypted LDAP and START_TLS.
202 202 Defaults to 636 for LDAPS.
203 203
204 204 .. _ldap_account:
205 205
206 206 Account : optional
207 207 Only required if the LDAP server does not allow anonymous browsing of
208 208 records. This should be a special account for record browsing. This
209 209 will require `LDAP Password`_ below.
210 210
211 211 .. _LDAP Password:
212 212
213 213 Password : optional
214 214 Only required if the LDAP server does not allow anonymous browsing of
215 215 records.
216 216
217 217 .. _Enable LDAPS:
218 218
219 219 Connection Security : required
220 220 Defines the connection to LDAP server
221 221
222 222 PLAIN
223 223 Plain unencrypted LDAP connection.
224 224 This will by default use `Port`_ 389.
225 225
226 226 LDAPS
227 227 Use secure LDAPS connections according to `Certificate
228 228 Checks`_ configuration.
229 229 This will by default use `Port`_ 636.
230 230
231 231 START_TLS
232 232 Use START TLS according to `Certificate Checks`_ configuration on an
233 233 apparently "plain" LDAP connection.
234 234 This will by default use `Port`_ 389.
235 235
236 236 .. _Certificate Checks:
237 237
238 238 Certificate Checks : optional
239 239 How SSL certificates verification is handled -- this is only useful when
240 240 `Enable LDAPS`_ is enabled. Only DEMAND or HARD offer full SSL security
241 241 with mandatory certificate validation, while the other options are
242 242 susceptible to man-in-the-middle attacks.
243 243
244 244 NEVER
245 245 A serve certificate will never be requested or checked.
246 246
247 247 ALLOW
248 248 A server certificate is requested. Failure to provide a
249 249 certificate or providing a bad certificate will not terminate the
250 250 session.
251 251
252 252 TRY
253 253 A server certificate is requested. Failure to provide a
254 254 certificate does not halt the session; providing a bad certificate
255 255 halts the session.
256 256
257 257 DEMAND
258 258 A server certificate is requested and must be provided and
259 259 authenticated for the session to proceed.
260 260
261 261 HARD
262 262 The same as DEMAND.
263 263
264 264 .. _Custom CA Certificates:
265 265
266 266 Custom CA Certificates : optional
267 267 Directory used by OpenSSL to find CAs for validating the LDAP server certificate.
268 268 Python 2.7.10 and later default to using the system certificate store, and
269 269 this should thus not be necessary when using certificates signed by a CA
270 270 trusted by the system.
271 271 It can be set to something like `/etc/openldap/cacerts` on older systems or
272 272 if using self-signed certificates.
273 273
274 274 .. _Base DN:
275 275
276 276 Base DN : required
277 277 The Distinguished Name (DN) where searches for users will be performed.
278 278 Searches can be controlled by `LDAP Filter`_ and `LDAP Search Scope`_.
279 279
280 280 .. _LDAP Filter:
281 281
282 282 LDAP Filter : optional
283 283 A LDAP filter defined by RFC 2254. This is more useful when `LDAP
284 284 Search Scope`_ is set to SUBTREE. The filter is useful for limiting
285 285 which LDAP objects are identified as representing Users for
286 286 authentication. The filter is augmented by `Login Attribute`_ below.
287 287 This can commonly be left blank.
288 288
289 289 .. _LDAP Search Scope:
290 290
291 291 LDAP Search Scope : required
292 292 This limits how far LDAP will search for a matching object.
293 293
294 294 BASE
295 295 Only allows searching of `Base DN`_ and is usually not what you
296 296 want.
297 297
298 298 ONELEVEL
299 299 Searches all entries under `Base DN`_, but not Base DN itself.
300 300
301 301 SUBTREE
302 302 Searches all entries below `Base DN`_, but not Base DN itself.
303 303 When using SUBTREE `LDAP Filter`_ is useful to limit object
304 304 location.
305 305
306 306 .. _Login Attribute:
307 307
308 308 Login Attribute : required
309 309 The LDAP record attribute that will be matched as the USERNAME or
310 310 ACCOUNT used to connect to Kallithea. This will be added to `LDAP
311 311 Filter`_ for locating the User object. If `LDAP Filter`_ is specified as
312 312 "LDAPFILTER", `Login Attribute`_ is specified as "uid" and the user has
313 313 connected as "jsmith" then the `LDAP Filter`_ will be augmented as below
314 314 ::
315 315
316 316 (&(LDAPFILTER)(uid=jsmith))
317 317
318 318 .. _ldap_attr_firstname:
319 319
320 320 First Name Attribute : required
321 321 The LDAP record attribute which represents the user's first name.
322 322
323 323 .. _ldap_attr_lastname:
324 324
325 325 Last Name Attribute : required
326 326 The LDAP record attribute which represents the user's last name.
327 327
328 328 .. _ldap_attr_email:
329 329
330 330 Email Attribute : required
331 331 The LDAP record attribute which represents the user's email address.
332 332
333 333 If all data are entered correctly, and python-ldap_ is properly installed
334 334 users should be granted access to Kallithea with LDAP accounts. At this
335 335 time user information is copied from LDAP into the Kallithea user database.
336 336 This means that updates of an LDAP user object may not be reflected as a
337 337 user update in Kallithea.
338 338
339 339 If You have problems with LDAP access and believe You entered correct
340 340 information check out the Kallithea logs, any error messages sent from LDAP
341 341 will be saved there.
342 342
343 343 Active Directory
344 344 ^^^^^^^^^^^^^^^^
345 345
346 346 Kallithea can use Microsoft Active Directory for user authentication. This
347 347 is done through an LDAP or LDAPS connection to Active Directory. The
348 348 following LDAP configuration settings are typical for using Active
349 349 Directory ::
350 350
351 351 Base DN = OU=SBSUsers,OU=Users,OU=MyBusiness,DC=v3sys,DC=local
352 352 Login Attribute = sAMAccountName
353 353 First Name Attribute = givenName
354 354 Last Name Attribute = sn
355 355 Email Attribute = mail
356 356
357 357 All other LDAP settings will likely be site-specific and should be
358 358 appropriately configured.
359 359
360 360
361 361 Authentication by container or reverse-proxy
362 362 --------------------------------------------
363 363
364 364 Kallithea supports delegating the authentication
365 365 of users to its WSGI container, or to a reverse-proxy server through which all
366 366 clients access the application.
367 367
368 368 When these authentication methods are enabled in Kallithea, it uses the
369 369 username that the container/proxy (Apache or Nginx, etc.) provides and doesn't
370 370 perform the authentication itself. The authorization, however, is still done by
371 371 Kallithea according to its settings.
372 372
373 373 When a user logs in for the first time using these authentication methods,
374 374 a matching user account is created in Kallithea with default permissions. An
375 375 administrator can then modify it using Kallithea's admin interface.
376 376
377 377 It's also possible for an administrator to create accounts and configure their
378 378 permissions before the user logs in for the first time, using the :ref:`create-user` API.
379 379
380 380 Container-based authentication
381 381 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
382 382
383 383 In a container-based authentication setup, Kallithea reads the user name from
384 384 the ``REMOTE_USER`` server variable provided by the WSGI container.
385 385
386 386 After setting up your container (see `Apache with mod_wsgi`_), you'll need
387 387 to configure it to require authentication on the location configured for
388 388 Kallithea.
389 389
390 390 Proxy pass-through authentication
391 391 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
392 392
393 393 In a proxy pass-through authentication setup, Kallithea reads the user name
394 394 from the ``X-Forwarded-User`` request header, which should be configured to be
395 395 sent by the reverse-proxy server.
396 396
397 397 After setting up your proxy solution (see `Apache virtual host reverse proxy example`_,
398 398 `Apache as subdirectory`_ or `Nginx virtual host example`_), you'll need to
399 399 configure the authentication and add the username in a request header named
400 400 ``X-Forwarded-User``.
401 401
402 402 For example, the following config section for Apache sets a subdirectory in a
403 403 reverse-proxy setup with basic auth:
404 404
405 405 .. code-block:: apache
406 406
407 407 <Location /someprefix>
408 408 ProxyPass http://127.0.0.1:5000/someprefix
409 409 ProxyPassReverse http://127.0.0.1:5000/someprefix
410 410 SetEnvIf X-Url-Scheme https HTTPS=1
411 411
412 412 AuthType Basic
413 413 AuthName "Kallithea authentication"
414 414 AuthUserFile /srv/kallithea/.htpasswd
415 415 Require valid-user
416 416
417 417 RequestHeader unset X-Forwarded-User
418 418
419 419 RewriteEngine On
420 420 RewriteCond %{LA-U:REMOTE_USER} (.+)
421 421 RewriteRule .* - [E=RU:%1]
422 422 RequestHeader set X-Forwarded-User %{RU}e
423 423 </Location>
424 424
425 425 Setting metadata in container/reverse-proxy
426 426 """""""""""""""""""""""""""""""""""""""""""
427 427 When a new user account is created on the first login, Kallithea has no information about
428 428 the user's email and full name. So you can set some additional request headers like in the
429 429 example below. In this example the user is authenticated via Kerberos and an Apache
430 430 mod_python fixup handler is used to get the user information from a LDAP server. But you
431 431 could set the request headers however you want.
432 432
433 433 .. code-block:: apache
434 434
435 435 <Location /someprefix>
436 436 ProxyPass http://127.0.0.1:5000/someprefix
437 437 ProxyPassReverse http://127.0.0.1:5000/someprefix
438 438 SetEnvIf X-Url-Scheme https HTTPS=1
439 439
440 440 AuthName "Kerberos Login"
441 441 AuthType Kerberos
442 442 Krb5Keytab /etc/apache2/http.keytab
443 443 KrbMethodK5Passwd off
444 444 KrbVerifyKDC on
445 445 Require valid-user
446 446
447 447 PythonFixupHandler ldapmetadata
448 448
449 449 RequestHeader set X_REMOTE_USER %{X_REMOTE_USER}e
450 450 RequestHeader set X_REMOTE_EMAIL %{X_REMOTE_EMAIL}e
451 451 RequestHeader set X_REMOTE_FIRSTNAME %{X_REMOTE_FIRSTNAME}e
452 452 RequestHeader set X_REMOTE_LASTNAME %{X_REMOTE_LASTNAME}e
453 453 </Location>
454 454
455 455 .. code-block:: python
456 456
457 457 from mod_python import apache
458 458 import ldap
459 459
460 460 LDAP_SERVER = "ldaps://server.mydomain.com:636"
461 461 LDAP_USER = ""
462 462 LDAP_PASS = ""
463 463 LDAP_ROOT = "dc=mydomain,dc=com"
464 464 LDAP_FILTER = "sAMAccountName=%s"
465 465 LDAP_ATTR_LIST = ['sAMAccountName','givenname','sn','mail']
466 466
467 467 def fixuphandler(req):
468 468 if req.user is None:
469 469 # no user to search for
470 470 return apache.OK
471 471 else:
472 472 try:
473 473 if('\\' in req.user):
474 474 username = req.user.split('\\')[1]
475 475 elif('@' in req.user):
476 476 username = req.user.split('@')[0]
477 477 else:
478 478 username = req.user
479 479 l = ldap.initialize(LDAP_SERVER)
480 480 l.simple_bind_s(LDAP_USER, LDAP_PASS)
481 481 r = l.search_s(LDAP_ROOT, ldap.SCOPE_SUBTREE, LDAP_FILTER % username, attrlist=LDAP_ATTR_LIST)
482 482
483 483 req.subprocess_env['X_REMOTE_USER'] = username
484 484 req.subprocess_env['X_REMOTE_EMAIL'] = r[0][1]['mail'][0].lower()
485 485 req.subprocess_env['X_REMOTE_FIRSTNAME'] = "%s" % r[0][1]['givenname'][0]
486 486 req.subprocess_env['X_REMOTE_LASTNAME'] = "%s" % r[0][1]['sn'][0]
487 487 except Exception, e:
488 488 apache.log_error("error getting data from ldap %s" % str(e), apache.APLOG_ERR)
489 489
490 490 return apache.OK
491 491
492 492 .. note::
493 493 If you enable proxy pass-through authentication, make sure your server is
494 494 only accessible through the proxy. Otherwise, any client would be able to
495 495 forge the authentication header and could effectively become authenticated
496 496 using any account of their liking.
497 497
498 498
499 499 Integration with issue trackers
500 500 -------------------------------
501 501
502 502 Kallithea provides a simple integration with issue trackers. It's possible
503 503 to define a regular expression that will match an issue ID in commit messages,
504 504 and have that replaced with a URL to the issue. To enable this simply
505 505 uncomment the following variables in the ini file::
506 506
507 507 issue_pat = (?:^#|\s#)(\w+)
508 508 issue_server_link = https://issues.example.com/{repo}/issue/{id}
509 509 issue_prefix = #
510 510
511 511 ``issue_pat`` is the regular expression describing which strings in
512 512 commit messages will be treated as issue references. A match group in
513 513 parentheses should be used to specify the actual issue id.
514 514
515 515 The default expression matches issues in the format ``#<number>``, e.g., ``#300``.
516 516
517 517 Matched issue references are replaced with the link specified in
518 518 ``issue_server_link``. ``{id}`` is replaced with the issue ID, and
519 519 ``{repo}`` with the repository name. Since the # is stripped away,
520 520 ``issue_prefix`` is prepended to the link text. ``issue_prefix`` doesn't
521 521 necessarily need to be ``#``: if you set issue prefix to ``ISSUE-`` this will
522 522 generate a URL in the format:
523 523
524 524 .. code-block:: html
525 525
526 526 <a href="https://issues.example.com/example_repo/issue/300">ISSUE-300</a>
527 527
528 528 If needed, more than one pattern can be specified by appending a unique suffix to
529 529 the variables. For example::
530 530
531 531 issue_pat_wiki = (?:wiki-)(.+)
532 532 issue_server_link_wiki = https://wiki.example.com/{id}
533 533 issue_prefix_wiki = WIKI-
534 534
535 535 With these settings, wiki pages can be referenced as wiki-some-id, and every
536 536 such reference will be transformed into:
537 537
538 538 .. code-block:: html
539 539
540 540 <a href="https://wiki.example.com/some-id">WIKI-some-id</a>
541 541
542 542
543 543 Hook management
544 544 ---------------
545 545
546 546 Hooks can be managed in similar way to that used in ``.hgrc`` files.
547 547 To manage hooks, choose *Admin > Settings > Hooks*.
548 548
549 549 The built-in hooks cannot be modified, though they can be enabled or disabled in the *VCS* section.
550 550
551 551 To add another custom hook simply fill in the first textbox with
552 552 ``<name>.<hook_type>`` and the second with the hook path. Example hooks
553 553 can be found in ``kallithea.lib.hooks``.
554 554
555 555
556 556 Changing default encoding
557 557 -------------------------
558 558
559 559 By default, Kallithea uses UTF-8 encoding.
560 560 This is configurable as ``default_encoding`` in the .ini file.
561 561 This affects many parts in Kallithea including user names, filenames, and
562 562 encoding of commit messages. In addition Kallithea can detect if the ``chardet``
563 563 library is installed. If ``chardet`` is detected Kallithea will fallback to it
564 564 when there are encode/decode errors.
565 565
566 566
567 567 Celery configuration
568 568 --------------------
569 569
570 570 Kallithea can use the distributed task queue system Celery_ to run tasks like
571 571 cloning repositories or sending emails.
572 572
573 573 Kallithea will in most setups work perfectly fine out of the box (without
574 574 Celery), executing all tasks in the web server process. Some tasks can however
575 575 take some time to run and it can be better to run such tasks asynchronously in
576 576 a separate process so the web server can focus on serving web requests.
577 577
578 578 For installation and configuration of Celery, see the `Celery documentation`_.
579 579 Note that Celery requires a message broker service like RabbitMQ_ (recommended)
580 580 or Redis_.
581 581
582 582 The use of Celery is configured in the Kallithea ini configuration file.
583 583 To enable it, simply set::
584 584
585 585 use_celery = true
586 586
587 587 and add or change the ``celery.*`` and ``broker.*`` configuration variables.
588 588
589 589 Remember that the ini files use the format with '.' and not with '_' like
590 590 Celery. So for example setting `BROKER_HOST` in Celery means setting
591 591 `broker.host` in the configuration file.
592 592
593 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 600 .. note::
598 601 Make sure you run this command from the same virtualenv, and with the same
599 602 user that Kallithea runs.
600 603
601 604
602 605 HTTPS support
603 606 -------------
604 607
605 608 Kallithea will by default generate URLs based on the WSGI environment.
606 609
607 610 Alternatively, you can use some special configuration settings to control
608 611 directly which scheme/protocol Kallithea will use when generating URLs:
609 612
610 613 - With ``https_fixup = true``, the scheme will be taken from the
611 614 ``X-Url-Scheme``, ``X-Forwarded-Scheme`` or ``X-Forwarded-Proto`` HTTP header
612 615 (default ``http``).
613 616 - With ``force_https = true`` the default will be ``https``.
614 617 - With ``use_htsts = true``, Kallithea will set ``Strict-Transport-Security`` when using https.
615 618
616 619
617 620 Nginx virtual host example
618 621 --------------------------
619 622
620 623 Sample config for Nginx using proxy:
621 624
622 625 .. code-block:: nginx
623 626
624 627 upstream kallithea {
625 628 server 127.0.0.1:5000;
626 629 # add more instances for load balancing
627 630 #server 127.0.0.1:5001;
628 631 #server 127.0.0.1:5002;
629 632 }
630 633
631 634 ## gist alias
632 635 server {
633 636 listen 443;
634 637 server_name gist.example.com;
635 638 access_log /var/log/nginx/gist.access.log;
636 639 error_log /var/log/nginx/gist.error.log;
637 640
638 641 ssl on;
639 642 ssl_certificate gist.your.kallithea.server.crt;
640 643 ssl_certificate_key gist.your.kallithea.server.key;
641 644
642 645 ssl_session_timeout 5m;
643 646
644 647 ssl_protocols SSLv3 TLSv1;
645 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 649 ssl_prefer_server_ciphers on;
647 650
648 651 rewrite ^/(.+)$ https://kallithea.example.com/_admin/gists/$1;
649 652 rewrite (.*) https://kallithea.example.com/_admin/gists;
650 653 }
651 654
652 655 server {
653 656 listen 443;
654 657 server_name kallithea.example.com
655 658 access_log /var/log/nginx/kallithea.access.log;
656 659 error_log /var/log/nginx/kallithea.error.log;
657 660
658 661 ssl on;
659 662 ssl_certificate your.kallithea.server.crt;
660 663 ssl_certificate_key your.kallithea.server.key;
661 664
662 665 ssl_session_timeout 5m;
663 666
664 667 ssl_protocols SSLv3 TLSv1;
665 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 669 ssl_prefer_server_ciphers on;
667 670
668 671 ## uncomment root directive if you want to serve static files by nginx
669 672 ## requires static_files = false in .ini file
670 673 #root /srv/kallithea/kallithea/kallithea/public;
671 674 include /etc/nginx/proxy.conf;
672 675 location / {
673 676 try_files $uri @kallithea;
674 677 }
675 678
676 679 location @kallithea {
677 680 proxy_pass http://127.0.0.1:5000;
678 681 }
679 682
680 683 }
681 684
682 685 Here's the proxy.conf. It's tuned so it will not timeout on long
683 686 pushes or large pushes::
684 687
685 688 proxy_redirect off;
686 689 proxy_set_header Host $host;
687 690 ## needed for container auth
688 691 #proxy_set_header REMOTE_USER $remote_user;
689 692 #proxy_set_header X-Forwarded-User $remote_user;
690 693 proxy_set_header X-Url-Scheme $scheme;
691 694 proxy_set_header X-Host $http_host;
692 695 proxy_set_header X-Real-IP $remote_addr;
693 696 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
694 697 proxy_set_header Proxy-host $proxy_host;
695 698 proxy_buffering off;
696 699 proxy_connect_timeout 7200;
697 700 proxy_send_timeout 7200;
698 701 proxy_read_timeout 7200;
699 702 proxy_buffers 8 32k;
700 703 client_max_body_size 1024m;
701 704 client_body_buffer_size 128k;
702 705 large_client_header_buffers 8 64k;
703 706
704 707
705 708 Apache virtual host reverse proxy example
706 709 -----------------------------------------
707 710
708 711 Here is a sample configuration file for Apache using proxy:
709 712
710 713 .. code-block:: apache
711 714
712 715 <VirtualHost *:80>
713 716 ServerName kallithea.example.com
714 717
715 718 <Proxy *>
716 719 # For Apache 2.4 and later:
717 720 Require all granted
718 721
719 722 # For Apache 2.2 and earlier, instead use:
720 723 # Order allow,deny
721 724 # Allow from all
722 725 </Proxy>
723 726
724 727 #important !
725 728 #Directive to properly generate url (clone url) for Kallithea
726 729 ProxyPreserveHost On
727 730
728 731 #kallithea instance
729 732 ProxyPass / http://127.0.0.1:5000/
730 733 ProxyPassReverse / http://127.0.0.1:5000/
731 734
732 735 #to enable https use line below
733 736 #SetEnvIf X-Url-Scheme https HTTPS=1
734 737 </VirtualHost>
735 738
736 739 Additional tutorial
737 740 http://pylonsbook.com/en/1.1/deployment.html#using-apache-to-proxy-requests-to-pylons
738 741
739 742
740 743 Apache as subdirectory
741 744 ----------------------
742 745
743 746 Apache subdirectory part:
744 747
745 748 .. code-block:: apache
746 749
747 750 <Location /<someprefix> >
748 751 ProxyPass http://127.0.0.1:5000/<someprefix>
749 752 ProxyPassReverse http://127.0.0.1:5000/<someprefix>
750 753 SetEnvIf X-Url-Scheme https HTTPS=1
751 754 </Location>
752 755
753 756 Besides the regular apache setup you will need to add the following line
754 757 into ``[app:main]`` section of your .ini file::
755 758
756 759 filter-with = proxy-prefix
757 760
758 761 Add the following at the end of the .ini file::
759 762
760 763 [filter:proxy-prefix]
761 764 use = egg:PasteDeploy#prefix
762 765 prefix = /<someprefix>
763 766
764 767 then change ``<someprefix>`` into your chosen prefix
765 768
766 769
767 770 Apache with mod_wsgi
768 771 --------------------
769 772
770 773 Alternatively, Kallithea can be set up with Apache under mod_wsgi. For
771 774 that, you'll need to:
772 775
773 776 - Install mod_wsgi. If using a Debian-based distro, you can install
774 777 the package libapache2-mod-wsgi::
775 778
776 779 aptitude install libapache2-mod-wsgi
777 780
778 781 - Enable mod_wsgi::
779 782
780 783 a2enmod wsgi
781 784
782 785 - Add global Apache configuration to tell mod_wsgi that Python only will be
783 786 used in the WSGI processes and shouldn't be initialized in the Apache
784 787 processes::
785 788
786 789 WSGIRestrictEmbedded On
787 790
788 791 - Create a wsgi dispatch script, like the one below. Make sure you
789 792 check that the paths correctly point to where you installed Kallithea
790 793 and its Python Virtual Environment.
791 794 - Enable the ``WSGIScriptAlias`` directive for the WSGI dispatch script,
792 795 as in the following example. Once again, check the paths are
793 796 correctly specified.
794 797
795 798 Here is a sample excerpt from an Apache Virtual Host configuration file:
796 799
797 800 .. code-block:: apache
798 801
799 802 WSGIDaemonProcess kallithea processes=5 threads=1 maximum-requests=100 \
800 803 python-home=/srv/kallithea/venv
801 804 WSGIProcessGroup kallithea
802 805 WSGIScriptAlias / /srv/kallithea/dispatch.wsgi
803 806 WSGIPassAuthorization On
804 807
805 808 Or if using a dispatcher WSGI script with proper virtualenv activation:
806 809
807 810 .. code-block:: apache
808 811
809 812 WSGIDaemonProcess kallithea processes=5 threads=1 maximum-requests=100
810 813 WSGIProcessGroup kallithea
811 814 WSGIScriptAlias / /srv/kallithea/dispatch.wsgi
812 815 WSGIPassAuthorization On
813 816
814 817 Apache will by default run as a special Apache user, on Linux systems
815 818 usually ``www-data`` or ``apache``. If you need to have the repositories
816 819 directory owned by a different user, use the user and group options to
817 820 WSGIDaemonProcess to set the name of the user and group.
818 821
819 822 Example WSGI dispatch script:
820 823
821 824 .. code-block:: python
822 825
823 826 import os
824 827 os.environ["HGENCODING"] = "UTF-8"
825 828 os.environ['PYTHON_EGG_CACHE'] = '/srv/kallithea/.egg-cache'
826 829
827 830 # sometimes it's needed to set the current dir
828 831 os.chdir('/srv/kallithea/')
829 832
830 833 import site
831 834 site.addsitedir("/srv/kallithea/venv/lib/python2.7/site-packages")
832 835
833 836 ini = '/srv/kallithea/my.ini'
834 837 from paste.script.util.logging_config import fileConfig
835 838 fileConfig(ini)
836 839 from paste.deploy import loadapp
837 840 application = loadapp('config:' + ini)
838 841
839 842 Or using proper virtualenv activation:
840 843
841 844 .. code-block:: python
842 845
843 846 activate_this = '/srv/kallithea/venv/bin/activate_this.py'
844 847 execfile(activate_this, dict(__file__=activate_this))
845 848
846 849 import os
847 850 os.environ['HOME'] = '/srv/kallithea'
848 851
849 852 ini = '/srv/kallithea/kallithea.ini'
850 853 from paste.script.util.logging_config import fileConfig
851 854 fileConfig(ini)
852 855 from paste.deploy import loadapp
853 856 application = loadapp('config:' + ini)
854 857
855 858
856 859 Other configuration files
857 860 -------------------------
858 861
859 862 A number of `example init.d scripts`__ can be found in
860 863 the ``init.d`` directory of the Kallithea source.
861 864
862 865 .. __: https://kallithea-scm.org/repos/kallithea/files/tip/init.d/ .
863 866
864 867
865 868 .. _virtualenv: http://pypi.python.org/pypi/virtualenv
866 869 .. _python: http://www.python.org/
867 870 .. _Mercurial: https://www.mercurial-scm.org/
868 871 .. _Celery: http://celeryproject.org/
869 872 .. _Celery documentation: http://docs.celeryproject.org/en/latest/getting-started/index.html
870 873 .. _RabbitMQ: http://www.rabbitmq.com/
871 874 .. _Redis: http://redis.io/
872 875 .. _python-ldap: http://www.python-ldap.org/
873 876 .. _mercurial-server: http://www.lshift.net/mercurial-server.html
874 877 .. _PublishingRepositories: https://www.mercurial-scm.org/wiki/PublishingRepositories
@@ -1,187 +1,187 b''
1 1 .. _upgrade:
2 2
3 3 ===================
4 4 Upgrading Kallithea
5 5 ===================
6 6
7 7 This describes the process for upgrading Kallithea, independently of the
8 8 Kallithea installation method.
9 9
10 10 .. note::
11 11 If you are upgrading from a RhodeCode installation, you must first
12 12 install Kallithea 0.3.2 and follow the instructions in the 0.3.2
13 13 README to perform a one-time conversion of the database from
14 14 RhodeCode to Kallithea, before upgrading to the latest version
15 15 of Kallithea.
16 16
17 17
18 18 1. Stop the Kallithea web application
19 19 -------------------------------------
20 20
21 21 This step depends entirely on the web server software used to serve
22 22 Kallithea, but in any case, Kallithea should not be running during
23 23 the upgrade.
24 24
25 25 .. note::
26 26 If you're using Celery, make sure you stop all instances during the
27 27 upgrade.
28 28
29 29
30 30 2. Create a backup of both database and configuration
31 31 -----------------------------------------------------
32 32
33 33 You are of course strongly recommended to make backups regularly, but it
34 34 is *especially* important to make a full database and configuration
35 35 backup before performing a Kallithea upgrade.
36 36
37 37 Back up your configuration
38 38 ^^^^^^^^^^^^^^^^^^^^^^^^^^
39 39
40 40 Make a copy of your Kallithea configuration (``.ini``) file.
41 41
42 42 If you are using :ref:`rcextensions <customization>`, you should also
43 43 make a copy of the entire ``rcextensions`` directory.
44 44
45 45 Back up your database
46 46 ^^^^^^^^^^^^^^^^^^^^^
47 47
48 48 If using SQLite, simply make a copy of the Kallithea database (``.db``)
49 49 file.
50 50
51 51 If using PostgreSQL, please consult the documentation for the ``pg_dump``
52 52 utility.
53 53
54 54 If using MySQL, please consult the documentation for the ``mysqldump``
55 55 utility.
56 56
57 57 Look for ``sqlalchemy.url`` in your configuration file to determine
58 58 database type, settings, location, etc.
59 59
60 60
61 61 3. Activate the Kallithea virtual environment (if any)
62 62 ------------------------------------------------------
63 63
64 64 Verify that you are using the Python environment that you originally
65 65 installed Kallithea in by running::
66 66
67 67 pip freeze
68 68
69 69 This will list all packages installed in the current environment. If
70 70 Kallithea isn't listed, activate the correct virtual environment.
71 71 See the appropriate installation page for details.
72 72
73 73
74 74 4. Install new version of Kallithea
75 75 -----------------------------------
76 76
77 77 Please refer to the instructions for the installation method you
78 78 originally used to install Kallithea.
79 79
80 80 If you originally installed using pip, it is as simple as::
81 81
82 82 pip install --upgrade kallithea
83 83
84 84 If you originally installed from version control, it is as simple as::
85 85
86 86 cd my-kallithea-clone
87 87 hg pull -u
88 88 pip install -e .
89 89
90 90
91 91 5. Upgrade your configuration
92 92 -----------------------------
93 93
94 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 98 This will display any changes made by the new version of Kallithea to your
99 99 current configuration, and attempt an automatic merge. It is recommended
100 100 that you check the contents after the merge.
101 101
102 102 .. note::
103 103 Please always make sure your ``.ini`` files are up to date. Errors
104 104 can often be caused by missing parameters added in new versions.
105 105
106 106 .. _upgrade_db:
107 107
108 108
109 109 6. Upgrade your database
110 110 ------------------------
111 111
112 112 .. note::
113 113 If you are *downgrading* Kallithea, you should perform the database
114 114 migration step *before* installing the older version. (That is,
115 115 always perform migrations using the most recent of the two versions
116 116 you're migrating between.)
117 117
118 118 First, run the following command to see your current database version::
119 119
120 120 alembic -c my.ini current
121 121
122 122 Typical output will be something like "9358dc3d6828 (head)", which is
123 123 the current Alembic database "revision ID". Write down the entire output
124 124 for troubleshooting purposes.
125 125
126 126 The output will be empty if you're upgrading from Kallithea 0.3.x or
127 127 older. That's expected. If you get an error that the config file was not
128 128 found or has no ``[alembic]`` section, see the next section.
129 129
130 130 Next, if you are performing an *upgrade*: Run the following command to
131 131 upgrade your database to the current Kallithea version::
132 132
133 133 alembic -c my.ini upgrade head
134 134
135 135 If you are performing a *downgrade*: Run the following command to
136 136 downgrade your database to the given version::
137 137
138 138 alembic -c my.ini downgrade 0.4
139 139
140 140 Alembic will show the necessary migrations (if any) as it executes them.
141 141 If no "ERROR" is displayed, the command was successful.
142 142
143 143 Should an error occur, the database may be "stranded" half-way
144 144 through the migration, and you should restore it from backup.
145 145
146 146 Enabling old Kallithea config files for Alembic use
147 147 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
148 148
149 149 Kallithea configuration files created before the introduction of Alembic
150 150 (i.e. predating Kallithea 0.4) need to be updated for use with Alembic.
151 151 Without this, Alembic will fail with an error like this::
152 152
153 153 FAILED: No config file 'my.ini' found, or file has no '[alembic]' section
154 154
155 155 If Alembic complains specifically about a missing ``alembic.ini``, it is
156 156 likely because you did not specify a config file using the ``-c`` option.
157 157 On the other hand, if the mentioned config file actually exists, you
158 158 need to append the following lines to it::
159 159
160 160 [alembic]
161 161 script_location = kallithea:alembic
162 162
163 163 Your config file should now work with Alembic.
164 164
165 165
166 166 7. Rebuild the Whoosh full-text index
167 167 -------------------------------------
168 168
169 169 It is recommended that you rebuild the Whoosh index after upgrading since
170 170 new Whoosh versions can introduce incompatible index changes.
171 171
172 172
173 173 8. Start the Kallithea web application
174 174 --------------------------------------
175 175
176 176 This step once again depends entirely on the web server software used to
177 177 serve Kallithea.
178 178
179 179 Before starting the new version of Kallithea, you may find it helpful to
180 180 clear out your log file so that new errors are readily apparent.
181 181
182 182 .. note::
183 183 If you're using Celery, make sure you restart all instances of it after
184 184 upgrade.
185 185
186 186
187 187 .. _virtualenv: http://pypi.python.org/pypi/virtualenv
@@ -1,50 +1,50 b''
1 1 .. _customization:
2 2
3 3 =============
4 4 Customization
5 5 =============
6 6
7 7 There are several ways to customize Kallithea to your needs depending on what
8 8 you want to achieve.
9 9
10 10
11 11 HTML/JavaScript/CSS customization
12 12 ---------------------------------
13 13
14 14 To customize the look-and-feel of the web interface (for example to add a
15 15 company banner or some JavaScript widget or to tweak the CSS style definitions)
16 16 you can enter HTML code (possibly with JavaScript and/or CSS) directly via the
17 17 *Admin > Settings > Global > HTML/JavaScript customization
18 18 block*.
19 19
20 20
21 21 Behavioral customization: rcextensions
22 22 --------------------------------------
23 23
24 24 Some behavioral customization can be done in Python using ``rcextensions``, a
25 25 custom Python package that can extend Kallithea functionality.
26 26
27 27 With ``rcextensions`` it's possible to add additional mappings for Whoosh
28 28 indexing and statistics, to add additional code into the push/pull/create/delete
29 29 repository hooks (for example to send signals to build bots such as Jenkins) and
30 30 even to monkey-patch certain parts of the Kallithea source code (for example
31 31 overwrite an entire function, change a global variable, ...).
32 32
33 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 37 This will create an ``rcextensions`` package next to the specified ``ini`` file.
38 38 See the ``__init__.py`` file inside the generated ``rcextensions`` package
39 39 for more details.
40 40
41 41
42 42 Behavioral customization: code changes
43 43 --------------------------------------
44 44
45 45 As Kallithea is open-source software, you can make any changes you like directly
46 46 in the source code.
47 47
48 48 We encourage you to send generic improvements back to the
49 49 community so that Kallithea can become better. See :ref:`contributing` for more
50 50 details.
@@ -1,181 +1,181 b''
1 1 .. _general:
2 2
3 3 =======================
4 4 General Kallithea usage
5 5 =======================
6 6
7 7
8 8 Repository deletion
9 9 -------------------
10 10
11 11 Currently when an admin or owner deletes a repository, Kallithea does
12 12 not physically delete said repository from the filesystem, but instead
13 13 renames it in a special way so that it is not possible to push, clone
14 14 or access the repository.
15 15
16 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 20 This command scans for archived repositories that are older than
21 21 30 days, displays them, and asks if you want to delete them (unless given
22 22 the ``--dont-ask`` flag). If you host a large amount of repositories with
23 23 forks that are constantly being deleted, it is recommended that you run this
24 24 command via crontab.
25 25
26 26 It is worth noting that even if someone is given administrative access to
27 27 Kallithea and deletes a repository, you can easily restore such an action by
28 28 renaming the repository directory, removing the ``rm__<date>`` prefix.
29 29
30 30
31 31 File view: follow current branch
32 32 --------------------------------
33 33
34 34 In the file view, left and right arrows allow to jump to the previous and next
35 35 revision. Depending on the way revisions were created in the repository, this
36 36 could jump to a different branch. When the checkbox ``Follow current branch``
37 37 is checked, these arrows will only jump to revisions on the same branch as the
38 38 currently visible revision. So for example, if someone is viewing files in the
39 39 ``beta`` branch and marks the `Follow current branch` checkbox, the < and >
40 40 arrows will only show revisions on the ``beta`` branch.
41 41
42 42
43 43 Changelog features
44 44 ------------------
45 45
46 46 The core feature of a repository's ``changelog`` page is to show the revisions
47 47 in a repository. However, there are several other features available from the
48 48 changelog.
49 49
50 50 Branch filter
51 51 By default, the changelog shows revisions from all branches in the
52 52 repository. Use the branch filter to restrict to a given branch.
53 53
54 54 Viewing a changeset
55 55 A particular changeset can be opened by clicking on either the changeset
56 56 hash or the commit message, or by ticking the checkbox and clicking the
57 57 ``Show selected changeset`` button at the top.
58 58
59 59 Viewing all changes between two changesets
60 60 To get a list of all changesets between two selected changesets, along with
61 61 the changes in each one of them, tick the checkboxes of the first and
62 62 last changeset in the desired range and click the ``Show selected changesets``
63 63 button at the top. You can only show the range between the first and last
64 64 checkbox (no cherry-picking).
65 65
66 66 From that page, you can proceed to viewing the overall delta between the
67 67 selected changesets, by clicking the ``Compare revisions`` button.
68 68
69 69 Creating a pull request
70 70 You can create a new pull request for the changes of a particular changeset
71 71 (and its ancestors) by selecting it and clicking the ``Open new pull request
72 72 for selected changesets`` button.
73 73
74 74
75 75 Permanent repository URLs
76 76 -------------------------
77 77
78 78 Due to the complicated nature of repository grouping, URLs of repositories
79 79 can often change. For example, a repository originally accessible from::
80 80
81 81 http://kallithea.example.com/repo_name
82 82
83 83 would get a new URL after moving it to test_group::
84 84
85 85 http://kallithea.example.com/test_group/repo_name
86 86
87 87 Such moving of a repository to a group can be an issue for build systems and
88 88 other scripts where the repository paths are hardcoded. To mitigate this,
89 89 Kallithea provides permanent URLs using the repository ID prefixed with an
90 90 underscore. In all Kallithea URLs, for example those for the changelog and the
91 91 file view, a repository name can be replaced by this ``_ID`` string. Since IDs
92 92 are always the same, moving the repository to a different group will not affect
93 93 such URLs.
94 94
95 95 In the example, the repository could also be accessible as::
96 96
97 97 http://kallithea.example.com/_<ID>
98 98
99 99 The ID of a given repository can be shown from the repository ``Summary`` page,
100 100 by selecting the ``Show by ID`` button next to ``Clone URL``.
101 101
102 102
103 103 Email notifications
104 104 -------------------
105 105
106 106 With email settings properly configured in the Kallithea
107 107 configuration file, Kallithea will send emails on user registration and when
108 108 errors occur.
109 109
110 110 Emails are also sent for comments on changesets. In this case, an email is sent
111 111 to the committer of the changeset (if known to Kallithea), to all reviewers of
112 112 the pull request (if applicable) and to all people mentioned in the comment
113 113 using @mention notation.
114 114
115 115
116 116 Trending source files
117 117 ---------------------
118 118
119 119 Trending source files are calculated based on a predefined dictionary of known
120 120 types and extensions. If an extension is missing or you would like to scan
121 121 custom files, it is possible to extend the ``LANGUAGES_EXTENSIONS_MAP``
122 122 dictionary located in ``kallithea/config/conf.py`` with new types.
123 123
124 124
125 125 Cloning remote repositories
126 126 ---------------------------
127 127
128 128 Kallithea has the ability to clone repositories from given remote locations.
129 129 Currently it supports the following options:
130 130
131 131 - hg -> hg clone
132 132 - svn -> hg clone
133 133 - git -> git clone
134 134
135 135 .. note:: svn -> hg cloning requires the ``hgsubversion`` library to be
136 136 installed.
137 137
138 138 If you need to clone repositories that are protected via basic authentication,
139 139 you can pass the credentials in the URL, e.g.
140 140 ``http://user:passw@remote.example.com/repo``. Kallithea will then try to login and
141 141 clone using the given credentials. Please note that the given credentials will
142 142 be stored as plaintext inside the database. However, the authentication
143 143 information will not be shown in the clone URL on the summary page.
144 144
145 145
146 146 Specific features configurable in the Admin settings
147 147 ----------------------------------------------------
148 148
149 149 In general, the Admin settings should be self-explanatory and will not be
150 150 described in more detail in this documentation. However, there are a few
151 151 features that merit further explanation.
152 152
153 153 Repository extra fields
154 154 ^^^^^^^^^^^^^^^^^^^^^^^
155 155
156 156 In the *Visual* tab, there is an option "Use repository extra
157 157 fields", which allows to set custom fields for each repository in the system.
158 158
159 159 Once enabled site-wide, the custom fields can be edited per-repository under
160 160 *Options* | *Settings* | *Extra Fields*.
161 161
162 162 Example usage of such fields would be to define company-specific information
163 163 into repositories, e.g., defining a ``repo_manager`` key that would give info
164 164 about a manager of each repository. There's no limit for adding custom fields.
165 165 Newly created fields are accessible via the API.
166 166
167 167 Meta tagging
168 168 ^^^^^^^^^^^^
169 169
170 170 In the *Visual* tab, option "Stylify recognised meta tags" will cause Kallithea
171 171 to turn certain text fragments in repository and repository group
172 172 descriptions into colored tags. Currently recognised tags are::
173 173
174 174 [featured]
175 175 [stale]
176 176 [dead]
177 177 [lang => lang]
178 178 [license => License]
179 179 [requires => Repo]
180 180 [recommends => Repo]
181 181 [see => URI]
@@ -1,87 +1,87 b''
1 1 .. _vcs_support:
2 2
3 3 ===============================
4 4 Version control systems support
5 5 ===============================
6 6
7 7 Kallithea supports Git and Mercurial repositories out-of-the-box.
8 8 For Git, you do need the ``git`` command line client installed on the server.
9 9
10 10 You can always disable Git or Mercurial support by editing the
11 11 file ``kallithea/__init__.py`` and commenting out the backend.
12 12
13 13 .. code-block:: python
14 14
15 15 BACKENDS = {
16 16 'hg': 'Mercurial repository',
17 17 #'git': 'Git repository',
18 18 }
19 19
20 20
21 21 Git support
22 22 -----------
23 23
24 24
25 25 Web server with chunked encoding
26 26 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
27 27
28 28 Large Git pushes require an HTTP server with support for
29 29 chunked encoding for POST. The Python web servers waitress_ and
30 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 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 36 use = egg:waitress#main
37 37
38 38 or::
39 39
40 40 use = egg:gunicorn#main
41 41
42 42 Also make sure to comment out the following options::
43 43
44 44 threadpool_workers =
45 45 threadpool_max_requests =
46 46 use_threadpool =
47 47
48 48
49 49 Mercurial support
50 50 -----------------
51 51
52 52
53 53 Working with Mercurial subrepositories
54 54 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
55 55
56 56 This section explains how to use Mercurial subrepositories_ in Kallithea.
57 57
58 58 Example usage::
59 59
60 60 ## init a simple repo
61 61 hg init mainrepo
62 62 cd mainrepo
63 63 echo "file" > file
64 64 hg add file
65 65 hg ci --message "initial file"
66 66
67 67 # clone subrepo we want to add from Kallithea
68 68 hg clone http://kallithea.local/subrepo
69 69
70 70 ## specify URL to existing repo in Kallithea as subrepository path
71 71 echo "subrepo = http://kallithea.local/subrepo" > .hgsub
72 72 hg add .hgsub
73 73 hg ci --message "added remote subrepo"
74 74
75 75 In the file list of a clone of ``mainrepo`` you will see a connected
76 76 subrepository at the revision it was cloned with. Clicking on the
77 77 subrepository link sends you to the proper repository in Kallithea.
78 78
79 79 Cloning ``mainrepo`` will also clone the attached subrepository.
80 80
81 81 Next we can edit the subrepository data, and push back to Kallithea. This will
82 82 update both repositories.
83 83
84 84
85 85 .. _waitress: http://pypi.python.org/pypi/waitress
86 86 .. _gunicorn: http://pypi.python.org/pypi/gunicorn
87 87 .. _subrepositories: http://mercurial.aragost.com/kick-start/en/subrepositories/
@@ -1,34 +1,34 b''
1 1 # celeryd - run the celeryd daemon as an upstart job for kallithea
2 2 # Change variables/paths as necessary and place file /etc/init/celeryd.conf
3 3 # start/stop/restart as normal upstart job (ie: $ start celeryd)
4 4
5 5 description "Celery for Kallithea Mercurial Server"
6 6 author "Matt Zuba <matt.zuba@goodwillaz.org"
7 7
8 8 start on starting kallithea
9 9 stop on stopped kallithea
10 10
11 11 respawn
12 12
13 13 umask 0022
14 14
15 15 env PIDFILE=/tmp/celeryd.pid
16 16 env APPINI=/var/hg/kallithea/production.ini
17 17 env HOME=/var/hg
18 18 env USER=hg
19 19 # To use group (if different from user), you must edit sudoers file and change
20 20 # root's entry from (ALL) to (ALL:ALL)
21 21 # env GROUP=hg
22 22
23 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 25 if [ -z "$GROUP" ]; then
26 26 exec sudo -u $USER $COMMAND
27 27 else
28 28 exec sudo -u $USER -g $GROUP $COMMAND
29 29 fi
30 30 end script
31 31
32 32 post-stop script
33 33 rm -f $PIDFILE
34 34 end script
@@ -1,70 +1,70 b''
1 1 #!/bin/bash
2 2 ###########################################
3 3 #### THIS IS AN ARCH LINUX RC.D SCRIPT ####
4 4 ###########################################
5 5
6 6 . /etc/rc.conf
7 7 . /etc/rc.d/functions
8 8
9 9 DAEMON=kallithea
10 10 APP_HOMEDIR="/srv"
11 11 APP_PATH="$APP_HOMEDIR/$DAEMON"
12 12 CONF_NAME="production.ini"
13 13 LOG_FILE="/var/log/$DAEMON.log"
14 14 PID_FILE="/run/daemons/$DAEMON"
15 APPL=/usr/bin/paster
15 APPL=/usr/bin/gearbox
16 16 RUN_AS="*****"
17 17
18 18 ARGS="serve --daemon \
19 19 --user=$RUN_AS \
20 20 --group=$RUN_AS \
21 21 --pid-file=$PID_FILE \
22 22 --log-file=$LOG_FILE \
23 $APP_PATH/$CONF_NAME"
23 -c $APP_PATH/$CONF_NAME"
24 24
25 25 [ -r /etc/conf.d/$DAEMON ] && . /etc/conf.d/$DAEMON
26 26
27 27 if [[ -r $PID_FILE ]]; then
28 28 read -r PID < "$PID_FILE"
29 29 if [[ $PID && ! -d /proc/$PID ]]; then
30 30 unset PID
31 31 rm_daemon $DAEMON
32 32 fi
33 33 fi
34 34
35 35 case "$1" in
36 36 start)
37 37 stat_busy "Starting $DAEMON"
38 38 export HOME=$APP_PATH
39 39 [ -z "$PID" ] && $APPL $ARGS &>/dev/null
40 40 if [ $? = 0 ]; then
41 41 add_daemon $DAEMON
42 42 stat_done
43 43 else
44 44 stat_fail
45 45 exit 1
46 46 fi
47 47 ;;
48 48 stop)
49 49 stat_busy "Stopping $DAEMON"
50 50 [ -n "$PID" ] && kill $PID &>/dev/null
51 51 if [ $? = 0 ]; then
52 52 rm_daemon $DAEMON
53 53 stat_done
54 54 else
55 55 stat_fail
56 56 exit 1
57 57 fi
58 58 ;;
59 59 restart)
60 60 $0 stop
61 61 sleep 1
62 62 $0 start
63 63 ;;
64 64 status)
65 65 stat_busy "Checking $name status";
66 66 ck_status $name
67 67 ;;
68 68 *)
69 69 echo "usage: $0 {start|stop|restart|status}"
70 70 esac
@@ -1,90 +1,90 b''
1 1 #!/bin/sh -e
2 2 ########################################
3 3 #### THIS IS A DEBIAN INIT.D SCRIPT ####
4 4 ########################################
5 5
6 6 ### BEGIN INIT INFO
7 7 # Provides: kallithea
8 8 # Required-Start: $all
9 9 # Required-Stop: $all
10 10 # Default-Start: 2 3 4 5
11 11 # Default-Stop: 0 1 6
12 12 # Short-Description: starts instance of kallithea
13 13 # Description: starts instance of kallithea using start-stop-daemon
14 14 ### END INIT INFO
15 15
16 16 APP_NAME="kallithea"
17 17 APP_HOMEDIR="opt"
18 18 APP_PATH="/$APP_HOMEDIR/$APP_NAME"
19 19
20 20 CONF_NAME="production.ini"
21 21
22 22 PID_PATH="$APP_PATH/$APP_NAME.pid"
23 23 LOG_PATH="$APP_PATH/$APP_NAME.log"
24 24
25 25 PYTHON_PATH="/$APP_HOMEDIR/$APP_NAME-venv"
26 26
27 27 RUN_AS="root"
28 28
29 DAEMON="$PYTHON_PATH/bin/paster"
29 DAEMON="$PYTHON_PATH/bin/gearbox"
30 30
31 31 DAEMON_OPTS="serve --daemon \
32 32 --user=$RUN_AS \
33 33 --group=$RUN_AS \
34 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 38 start() {
39 39 echo "Starting $APP_NAME"
40 40 PYTHON_EGG_CACHE="/tmp" start-stop-daemon -d $APP_PATH \
41 41 --start --quiet \
42 42 --pidfile $PID_PATH \
43 43 --user $RUN_AS \
44 44 --exec $DAEMON -- $DAEMON_OPTS
45 45 }
46 46
47 47 stop() {
48 48 echo "Stopping $APP_NAME"
49 49 start-stop-daemon -d $APP_PATH \
50 50 --stop --quiet \
51 51 --pidfile $PID_PATH || echo "$APP_NAME - Not running!"
52 52
53 53 if [ -f $PID_PATH ]; then
54 54 rm $PID_PATH
55 55 fi
56 56 }
57 57
58 58 status() {
59 59 echo -n "Checking status of $APP_NAME ... "
60 60 pid=`cat $PID_PATH`
61 61 status=`ps ax | grep $pid | grep -ve grep`
62 62 if [ "$?" -eq 0 ]; then
63 63 echo "running"
64 64 else
65 65 echo "NOT running"
66 66 fi
67 67 }
68 68
69 69 case "$1" in
70 70 status)
71 71 status
72 72 ;;
73 73 start)
74 74 start
75 75 ;;
76 76 stop)
77 77 stop
78 78 ;;
79 79 restart)
80 80 echo "Restarting $APP_NAME"
81 81 ### stop ###
82 82 stop
83 83 wait
84 84 ### start ###
85 85 start
86 86 ;;
87 87 *)
88 88 echo "Usage: $0 {start|stop|restart}"
89 89 exit 1
90 90 esac
@@ -1,61 +1,61 b''
1 1 #!/sbin/runscript
2 2 ########################################
3 3 #### THIS IS AN GENTOO INIT.D SCRIPT####
4 4 ########################################
5 5
6 6 APP_NAME="kallithea"
7 7 APP_HOMEDIR="username/python_workspace"
8 8 APP_PATH="/home/$APP_HOMEDIR/$APP_NAME"
9 9
10 10 CONF_NAME="production.ini"
11 11
12 12 PID_PATH="$APP_PATH/$APP_NAME.pid"
13 13 LOG_PATH="$APP_PATH/$APP_NAME.log"
14 14
15 15 PYTHON_PATH="/home/$APP_HOMEDIR/v-env"
16 16
17 17 RUN_AS="username"
18 18
19 DAEMON="$PYTHON_PATH/bin/paster"
19 DAEMON="$PYTHON_PATH/bin/gearbox"
20 20
21 21 DAEMON_OPTS="serve --daemon \
22 22 --user=$RUN_AS \
23 23 --group=$RUN_AS \
24 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 27 #extra options
28 28 opts="${opts} restartdelay"
29 29
30 30 depend() {
31 31 need nginx
32 32 }
33 33
34 34 start() {
35 35 ebegin "Starting $APP_NAME"
36 36 start-stop-daemon -d $APP_PATH -e PYTHON_EGG_CACHE="/tmp" \
37 37 --start --quiet \
38 38 --pidfile $PID_PATH \
39 39 --user $RUN_AS \
40 40 --exec $DAEMON -- $DAEMON_OPTS
41 41 eend $?
42 42 }
43 43
44 44 stop() {
45 45 ebegin "Stopping $APP_NAME"
46 46 start-stop-daemon -d $APP_PATH \
47 47 --stop --quiet \
48 48 --pidfile $PID_PATH || echo "$APP_NAME - Not running!"
49 49 if [ -f $PID_PATH ]; then
50 50 rm $PID_PATH
51 51 fi
52 52 eend $?
53 53 }
54 54
55 55 restartdelay() {
56 56 #stop()
57 57 echo "sleep3"
58 58 sleep 3
59 59
60 60 #start()
61 61 }
@@ -1,132 +1,132 b''
1 1 #!/bin/sh
2 2 ########################################
3 3 #### THIS IS A REDHAT INIT.D SCRIPT ####
4 4 ########################################
5 5
6 6 ##################################################
7 7 #
8 8 # Kallithea server startup script
9 9 # Recommended default-startup: 2 3 4 5
10 10 # Recommended default-stop: 0 1 6
11 11 #
12 12 ##################################################
13 13
14 14
15 15 APP_NAME="kallithea"
16 16 # the location of your app
17 17 # since this is a web app, it should go in /var/www
18 18 APP_PATH="/var/www/$APP_NAME"
19 19
20 20 CONF_NAME="production.ini"
21 21
22 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 24 # same goes for the log file
25 25 PID_PATH="/var/run/kallithea/pid"
26 26 LOG_PATH="/var/log/kallithea/kallithea.log"
27 27
28 28 # replace this with the path to the virtual environment you
29 29 # made for Kallithea
30 30 PYTHON_PATH="/opt/python_virtualenvironments/kallithea-venv"
31 31
32 32 RUN_AS="kallithea"
33 33
34 DAEMON="$PYTHON_PATH/bin/paster"
34 DAEMON="$PYTHON_PATH/bin/gearbox"
35 35
36 36 DAEMON_OPTS="serve --daemon \
37 37 --user=$RUN_AS \
38 38 --group=$RUN_AS \
39 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 42 DESC="kallithea-server"
43 43 LOCK_FILE="/var/lock/subsys/$APP_NAME"
44 44
45 45 # source CentOS init functions
46 46 . /etc/init.d/functions
47 47
48 48 RETVAL=0
49 49
50 50 remove_pid () {
51 51 rm -f ${PID_PATH}
52 52 rmdir `dirname ${PID_PATH}`
53 53 }
54 54
55 55 ensure_pid_dir () {
56 56 PID_DIR=`dirname ${PID_PATH}`
57 57 if [ ! -d ${PID_DIR} ] ; then
58 58 mkdir -p ${PID_DIR}
59 59 chown -R ${RUN_AS}:${RUN_AS} ${PID_DIR}
60 60 chmod 755 ${PID_DIR}
61 61 fi
62 62 }
63 63
64 64 start_kallithea () {
65 65 ensure_pid_dir
66 66 PYTHON_EGG_CACHE="/tmp" daemon --pidfile $PID_PATH \
67 67 --user $RUN_AS "$DAEMON $DAEMON_OPTS"
68 68 RETVAL=$?
69 69 [ $RETVAL -eq 0 ] && touch $LOCK_FILE
70 70 return $RETVAL
71 71 }
72 72
73 73 stop_kallithea () {
74 74 if [ -e $LOCK_FILE ]; then
75 75 killproc -p $PID_PATH
76 76 RETVAL=$?
77 77 rm -f $LOCK_FILE
78 78 rm -f $PID_PATH
79 79 else
80 80 RETVAL=1
81 81 fi
82 82 return $RETVAL
83 83 }
84 84
85 85 status_kallithea() {
86 86 if [ -e $LOCK_FILE ]; then
87 87 # exit with non-zero to indicate failure
88 88 RETVAL=1
89 89 else
90 90 RETVAL=0
91 91 fi
92 92 return $RETVAL
93 93 }
94 94
95 95 restart_kallithea () {
96 96 stop_kallithea
97 97 start_kallithea
98 98 RETVAL=$?
99 99 }
100 100
101 101 case "$1" in
102 102 start)
103 103 echo -n $"Starting $DESC: "
104 104 start_kallithea
105 105 echo
106 106 ;;
107 107 stop)
108 108 echo -n $"Stopping $DESC: "
109 109 stop_kallithea
110 110 echo
111 111 ;;
112 112 status)
113 113 status_kallithea
114 114 RETVAL=$?
115 115 if [ ! $RETVAL -eq 0 ]; then
116 116 echo "Kallithea server is running..."
117 117 else
118 118 echo "Kallithea server is stopped."
119 119 fi
120 120 ;;
121 121 restart)
122 122 echo -n $"Restarting $DESC: "
123 123 restart_kallithea
124 124 echo
125 125 ;;
126 126 *)
127 127 echo $"Usage: $0 {start|stop|restart|status}"
128 128 RETVAL=1
129 129 ;;
130 130 esac
131 131
132 132 exit $RETVAL
@@ -1,26 +1,26 b''
1 1 # kallithea - run the kallithea daemon as an upstart job
2 2 # Change variables/paths as necessary and place file /etc/init/kallithea.conf
3 3 # start/stop/restart as normal upstart job (ie: $ start kallithea)
4 4
5 5 description "Kallithea Mercurial Server"
6 6 author "Matt Zuba <matt.zuba@goodwillaz.org"
7 7
8 8 start on (local-filesystems and runlevel [2345])
9 9 stop on runlevel [!2345]
10 10
11 11 respawn
12 12
13 13 umask 0022
14 14
15 15 env PIDFILE=/var/hg/kallithea/kallithea.pid
16 16 env LOGFILE=/var/hg/kallithea/log/kallithea.log
17 17 env APPINI=/var/hg/kallithea/production.ini
18 18 env HOME=/var/hg
19 19 env USER=hg
20 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 24 post-stop script
25 25 rm -f $PIDFILE
26 26 end script
@@ -1,51 +1,51 b''
1 1 ; Kallithea Supervisord
2 2 ; ##########################
3 3 ; for help see http://supervisord.org/configuration.html
4 4 ; ##########################
5 5
6 6 [inet_http_server] ; inet (TCP) server disabled by default
7 7 port=127.0.0.1:9001 ; (ip_address:port specifier, *:port for all iface)
8 8 ;username=user ; (default is no username (open server))
9 9 ;password=123 ; (default is no password (open server))
10 10
11 11 [supervisord]
12 12 logfile=/%(here)s/supervisord_kallithea.log ; (main log file;default $CWD/supervisord.log)
13 13 logfile_maxbytes=50MB ; (max main logfile bytes b4 rotation;default 50MB)
14 14 logfile_backups=10 ; (num of main logfile rotation backups;default 10)
15 15 loglevel=info ; (log level;default info; others: debug,warn,trace)
16 16 pidfile=/%(here)s/supervisord_kallithea.pid ; (supervisord pidfile;default supervisord.pid)
17 17 nodaemon=true ; (start in foreground if true;default false)
18 18 minfds=1024 ; (min. avail startup file descriptors;default 1024)
19 19 minprocs=200 ; (min. avail process descriptors;default 200)
20 20 umask=022 ; (process file creation umask;default 022)
21 21 user=username ; (default is current user, required if root)
22 22 ;identifier=supervisor ; (supervisord identifier, default is 'supervisor')
23 23 ;directory=/tmp ; (default is not to cd during start)
24 24 ;nocleanup=true ; (don't clean up tempfiles at start;default false)
25 25 ;childlogdir=/tmp ; ('AUTO' child log dir, default $TEMP)
26 26 environment=HOME=/srv/kallithea ; (key value pairs to add to environment)
27 27 ;strip_ansi=false ; (strip ansi escape codes in logs; def. false)
28 28
29 29 ; the below section must remain in the config file for RPC
30 30 ; (supervisorctl/web interface) to work, additional interfaces may be
31 31 ; added by defining them in separate rpcinterface: sections
32 32 [rpcinterface:supervisor]
33 33 supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
34 34
35 35 [supervisorctl]
36 36 serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket
37 37 ;username=user ; should be same as http_username if set
38 38 ;password=123 ; should be same as http_password if set
39 39 ;prompt=mysupervisor ; cmd line prompt (default "supervisor")
40 40 ;history_file=~/.sc_history ; use readline history if available
41 41
42 42
43 43 ; restart with supervisorctl restart kallithea:*
44 44 [program:kallithea]
45 45 numprocs = 1
46 46 numprocs_start = 5000 # possible should match ports
47 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 49 process_name = %(program_name)s_%(process_num)04d
50 50 redirect_stderr=true
51 51 stdout_logfile=/%(here)s/kallithea.log
@@ -1,105 +1,105 b''
1 1 # -*- coding: utf-8 -*-
2 2 # This program is free software: you can redistribute it and/or modify
3 3 # it under the terms of the GNU General Public License as published by
4 4 # the Free Software Foundation, either version 3 of the License, or
5 5 # (at your option) any later version.
6 6 #
7 7 # This program is distributed in the hope that it will be useful,
8 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 # GNU General Public License for more details.
11 11 #
12 12 # You should have received a copy of the GNU General Public License
13 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14
15 15 # Alembic migration environment (configuration).
16 16
17 17 import logging
18 18 from logging.config import fileConfig
19 19
20 20 from alembic import context
21 21 from sqlalchemy import engine_from_config, pool
22 22
23 23 from kallithea.model import db
24 24
25 25
26 26 # The alembic.config.Config object, which wraps the current .ini file.
27 27 config = context.config
28 28
29 29 # Default to use the main Kallithea database string in [app:main].
30 30 # For advanced uses, this can be overridden by specifying an explicit
31 31 # [alembic] sqlalchemy.url.
32 32 database_url = (
33 33 config.get_main_option('sqlalchemy.url') or
34 34 config.get_section_option('app:main', 'sqlalchemy.url')
35 35 )
36 36
37 37 # Configure default logging for Alembic. (This can be overriden by the
38 38 # config file, but usually isn't.)
39 39 logging.getLogger('alembic').setLevel(logging.INFO)
40 40
41 41 # Setup Python loggers based on the config file provided to the alembic
42 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 44 # and loggers are assumed to already have been configured.
45 45 if config.config_file_name:
46 46 fileConfig(config.config_file_name, disable_existing_loggers=False)
47 47
48 48
49 49 def include_in_autogeneration(object, name, type, reflected, compare_to):
50 50 """Filter changes subject to autogeneration of migrations. """
51 51
52 52 # Don't include changes to sqlite_sequence.
53 53 if type == 'table' and name == 'sqlite_sequence':
54 54 return False
55 55
56 56 return True
57 57
58 58
59 59 def run_migrations_offline():
60 60 """Run migrations in 'offline' (--sql) mode.
61 61
62 62 This produces an SQL script instead of directly applying the changes.
63 63 Some migrations may not run in offline mode.
64 64 """
65 65 context.configure(
66 66 url=database_url,
67 67 literal_binds=True,
68 68 )
69 69
70 70 with context.begin_transaction():
71 71 context.run_migrations()
72 72
73 73
74 74 def run_migrations_online():
75 75 """Run migrations in 'online' mode.
76 76
77 77 Connects to the database and directly applies the necessary
78 78 migrations.
79 79 """
80 80 cfg = config.get_section(config.config_ini_section)
81 81 cfg['sqlalchemy.url'] = database_url
82 82 connectable = engine_from_config(
83 83 cfg,
84 84 prefix='sqlalchemy.',
85 85 poolclass=pool.NullPool)
86 86
87 87 with connectable.connect() as connection:
88 88 context.configure(
89 89 connection=connection,
90 90
91 91 # Support autogeneration of migration scripts based on "diff" between
92 92 # current database schema and kallithea.model.db schema.
93 93 target_metadata=db.Base.metadata,
94 94 include_object=include_in_autogeneration,
95 95 render_as_batch=True, # batch mode is needed for SQLite support
96 96 )
97 97
98 98 with context.begin_transaction():
99 99 context.run_migrations()
100 100
101 101
102 102 if context.is_offline_mode():
103 103 run_migrations_offline()
104 104 else:
105 105 run_migrations_online()
@@ -1,600 +1,610 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%text>################################################################################</%text>
3 3 <%text>################################################################################</%text>
4 4 # Kallithea - config file generated with kallithea-config #
5 5 <%text>################################################################################</%text>
6 6 <%text>################################################################################</%text>
7 7
8 8 [DEFAULT]
9 9 debug = true
10 10 pdebug = false
11 11
12 12 <%text>################################################################################</%text>
13 13 <%text>## Email settings ##</%text>
14 14 <%text>## ##</%text>
15 15 <%text>## Refer to the documentation ("Email settings") for more details. ##</%text>
16 16 <%text>## ##</%text>
17 17 <%text>## It is recommended to use a valid sender address that passes access ##</%text>
18 18 <%text>## validation and spam filtering in mail servers. ##</%text>
19 19 <%text>################################################################################</%text>
20 20
21 21 <%text>## 'From' header for application emails. You can optionally add a name.</%text>
22 22 <%text>## Default:</%text>
23 23 #app_email_from = Kallithea
24 24 <%text>## Examples:</%text>
25 25 #app_email_from = Kallithea <kallithea-noreply@example.com>
26 26 #app_email_from = kallithea-noreply@example.com
27 27
28 28 <%text>## Subject prefix for application emails.</%text>
29 29 <%text>## A space between this prefix and the real subject is automatically added.</%text>
30 30 <%text>## Default:</%text>
31 31 #email_prefix =
32 32 <%text>## Example:</%text>
33 33 #email_prefix = [Kallithea]
34 34
35 35 <%text>## Recipients for error emails and fallback recipients of application mails.</%text>
36 36 <%text>## Multiple addresses can be specified, space-separated.</%text>
37 37 <%text>## Only addresses are allowed, do not add any name part.</%text>
38 38 <%text>## Default:</%text>
39 39 #email_to =
40 40 <%text>## Examples:</%text>
41 41 #email_to = admin@example.com
42 42 #email_to = admin@example.com another_admin@example.com
43 43
44 44 <%text>## 'From' header for error emails. You can optionally add a name.</%text>
45 45 <%text>## Default:</%text>
46 46 #error_email_from = pylons@yourapp.com
47 47 <%text>## Examples:</%text>
48 48 #error_email_from = Kallithea Errors <kallithea-noreply@example.com>
49 49 #error_email_from = paste_error@example.com
50 50
51 51 <%text>## SMTP server settings</%text>
52 52 <%text>## If specifying credentials, make sure to use secure connections.</%text>
53 53 <%text>## Default: Send unencrypted unauthenticated mails to the specified smtp_server.</%text>
54 54 <%text>## For "SSL", use smtp_use_ssl = true and smtp_port = 465.</%text>
55 55 <%text>## For "STARTTLS", use smtp_use_tls = true and smtp_port = 587.</%text>
56 56 #smtp_server = smtp.example.com
57 57 #smtp_username =
58 58 #smtp_password =
59 59 #smtp_port = 25
60 60 #smtp_use_ssl = false
61 61 #smtp_use_tls = false
62 62
63 63 [server:main]
64 %if http_server == 'paste':
65 <%text>## PASTE ##</%text>
66 use = egg:Paste#http
64 %if http_server == 'gearbox':
65 <%text>## Gearbox default web server ##</%text>
66 use = egg:gearbox#wsgiref
67 67 <%text>## nr of worker threads to spawn</%text>
68 68 threadpool_workers = 1
69 69 <%text>## max request before thread respawn</%text>
70 70 threadpool_max_requests = 100
71 71 <%text>## option to use threads of process</%text>
72 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 78 %elif http_server == 'waitress':
75 79 <%text>## WAITRESS ##</%text>
76 80 use = egg:waitress#main
77 81 <%text>## number of worker threads</%text>
78 82 threads = 1
79 83 <%text>## MAX BODY SIZE 100GB</%text>
80 84 max_request_body_size = 107374182400
81 85 <%text>## use poll instead of select, fixes fd limits, may not work on old</%text>
82 86 <%text>## windows systems.</%text>
83 87 #asyncore_use_poll = True
84 88
85 89 %elif http_server == 'gunicorn':
86 90 <%text>## GUNICORN ##</%text>
87 91 use = egg:gunicorn#main
88 92 <%text>## number of process workers. You must set `instance_id = *` when this option</%text>
89 93 <%text>## is set to more than one worker</%text>
90 94 workers = 1
91 95 <%text>## process name</%text>
92 96 proc_name = kallithea
93 97 <%text>## type of worker class, one of sync, eventlet, gevent, tornado</%text>
94 98 <%text>## recommended for bigger setup is using of of other than sync one</%text>
95 99 worker_class = sync
96 100 max_requests = 1000
97 101 <%text>## amount of time a worker can handle request before it gets killed and</%text>
98 102 <%text>## restarted</%text>
99 103 timeout = 3600
100 104
101 105 %elif http_server == 'uwsgi':
102 106 <%text>## UWSGI ##</%text>
103 107 <%text>## run with uwsgi --ini-paste-logged <inifile.ini></%text>
104 108 [uwsgi]
105 109 socket = /tmp/uwsgi.sock
106 110 master = true
107 111 http = 127.0.0.1:5000
108 112
109 113 <%text>## set as deamon and redirect all output to file</%text>
110 114 #daemonize = ./uwsgi_kallithea.log
111 115
112 116 <%text>## master process PID</%text>
113 117 pidfile = ./uwsgi_kallithea.pid
114 118
115 119 <%text>## stats server with workers statistics, use uwsgitop</%text>
116 120 <%text>## for monitoring, `uwsgitop 127.0.0.1:1717`</%text>
117 121 stats = 127.0.0.1:1717
118 122 memory-report = true
119 123
120 124 <%text>## log 5XX errors</%text>
121 125 log-5xx = true
122 126
123 127 <%text>## Set the socket listen queue size.</%text>
124 128 listen = 256
125 129
126 130 <%text>## Gracefully Reload workers after the specified amount of managed requests</%text>
127 131 <%text>## (avoid memory leaks).</%text>
128 132 max-requests = 1000
129 133
130 134 <%text>## enable large buffers</%text>
131 135 buffer-size = 65535
132 136
133 137 <%text>## socket and http timeouts ##</%text>
134 138 http-timeout = 3600
135 139 socket-timeout = 3600
136 140
137 141 <%text>## Log requests slower than the specified number of milliseconds.</%text>
138 142 log-slow = 10
139 143
140 144 <%text>## Exit if no app can be loaded.</%text>
141 145 need-app = true
142 146
143 147 <%text>## Set lazy mode (load apps in workers instead of master).</%text>
144 148 lazy = true
145 149
146 150 <%text>## scaling ##</%text>
147 151 <%text>## set cheaper algorithm to use, if not set default will be used</%text>
148 152 cheaper-algo = spare
149 153
150 154 <%text>## minimum number of workers to keep at all times</%text>
151 155 cheaper = 1
152 156
153 157 <%text>## number of workers to spawn at startup</%text>
154 158 cheaper-initial = 1
155 159
156 160 <%text>## maximum number of workers that can be spawned</%text>
157 161 workers = 4
158 162
159 163 <%text>## how many workers should be spawned at a time</%text>
160 164 cheaper-step = 1
161 165
162 166 %endif
163 167 <%text>## COMMON ##</%text>
164 168 host = ${host}
165 169 port = ${port}
166 170
167 171 <%text>## middleware for hosting the WSGI application under a URL prefix</%text>
168 172 #[filter:proxy-prefix]
169 173 #use = egg:PasteDeploy#prefix
170 174 #prefix = /<your-prefix>
171 175
172 176 [app:main]
173 177 use = egg:kallithea
174 178 <%text>## enable proxy prefix middleware</%text>
175 179 #filter-with = proxy-prefix
176 180
177 181 full_stack = true
178 182 static_files = true
179 183 <%text>## Available Languages:</%text>
180 184 <%text>## cs de fr hu ja nl_BE pl pt_BR ru sk zh_CN zh_TW</%text>
181 185 lang =
182 186 cache_dir = ${here}/data
183 187 index_dir = ${here}/data/index
184 188
185 189 <%text>## perform a full repository scan on each server start, this should be</%text>
186 190 <%text>## set to false after first startup, to allow faster server restarts.</%text>
187 191 initial_repo_scan = false
188 192
189 193 <%text>## uncomment and set this path to use archive download cache</%text>
190 194 archive_cache_dir = ${here}/tarballcache
191 195
192 196 <%text>## change this to unique ID for security</%text>
193 197 app_instance_uuid = ${uuid()}
194 198
195 199 <%text>## cut off limit for large diffs (size in bytes)</%text>
196 200 cut_off_limit = 256000
197 201
198 202 <%text>## force https in Kallithea, fixes https redirects, assumes it's always https</%text>
199 203 force_https = false
200 204
201 205 <%text>## use Strict-Transport-Security headers</%text>
202 206 use_htsts = false
203 207
204 208 <%text>## number of commits stats will parse on each iteration</%text>
205 209 commit_parse_limit = 25
206 210
207 211 <%text>## path to git executable</%text>
208 212 git_path = git
209 213
210 214 <%text>## git rev filter option, --all is the default filter, if you need to</%text>
211 215 <%text>## hide all refs in changelog switch this to --branches --tags</%text>
212 216 #git_rev_filter = --branches --tags
213 217
214 218 <%text>## RSS feed options</%text>
215 219 rss_cut_off_limit = 256000
216 220 rss_items_per_page = 10
217 221 rss_include_diff = false
218 222
219 223 <%text>## options for showing and identifying changesets</%text>
220 224 show_sha_length = 12
221 225 show_revision_number = false
222 226
223 227 <%text>## Canonical URL to use when creating full URLs in UI and texts.</%text>
224 228 <%text>## Useful when the site is available under different names or protocols.</%text>
225 229 <%text>## Defaults to what is provided in the WSGI environment.</%text>
226 230 #canonical_url = https://kallithea.example.com/repos
227 231
228 232 <%text>## gist URL alias, used to create nicer urls for gist. This should be an</%text>
229 233 <%text>## url that does rewrites to _admin/gists/<gistid>.</%text>
230 234 <%text>## example: http://gist.example.com/{gistid}. Empty means use the internal</%text>
231 235 <%text>## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid></%text>
232 236 gist_alias_url =
233 237
234 238 <%text>## white list of API enabled controllers. This allows to add list of</%text>
235 239 <%text>## controllers to which access will be enabled by api_key. eg: to enable</%text>
236 240 <%text>## api access to raw_files put `FilesController:raw`, to enable access to patches</%text>
237 241 <%text>## add `ChangesetController:changeset_patch`. This list should be "," separated</%text>
238 242 <%text>## Syntax is <ControllerClass>:<function>. Check debug logs for generated names</%text>
239 243 <%text>## Recommended settings below are commented out:</%text>
240 244 api_access_controllers_whitelist =
241 245 # ChangesetController:changeset_patch,
242 246 # ChangesetController:changeset_raw,
243 247 # FilesController:raw,
244 248 # FilesController:archivefile
245 249
246 250 <%text>## default encoding used to convert from and to unicode</%text>
247 251 <%text>## can be also a comma separated list of encoding in case of mixed encodings</%text>
248 252 default_encoding = utf8
249 253
250 254 <%text>## issue tracker for Kallithea (leave blank to disable, absent for default)</%text>
251 255 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
252 256
253 257 <%text>## issue tracking mapping for commits messages</%text>
254 258 <%text>## comment out issue_pat, issue_server, issue_prefix to enable</%text>
255 259
256 260 <%text>## pattern to get the issues from commit messages</%text>
257 261 <%text>## default one used here is #<numbers> with a regex passive group for `#`</%text>
258 262 <%text>## {id} will be all groups matched from this pattern</%text>
259 263
260 264 issue_pat = (?:\s*#)(\d+)
261 265
262 266 <%text>## server url to the issue, each {id} will be replaced with match</%text>
263 267 <%text>## fetched from the regex and {repo} is replaced with full repository name</%text>
264 268 <%text>## including groups {repo_name} is replaced with just name of repo</%text>
265 269
266 270 issue_server_link = https://issues.example.com/{repo}/issue/{id}
267 271
268 272 <%text>## prefix to add to link to indicate it's an url</%text>
269 273 <%text>## #314 will be replaced by <issue_prefix><id></%text>
270 274
271 275 issue_prefix = #
272 276
273 277 <%text>## issue_pat, issue_server_link, issue_prefix can have suffixes to specify</%text>
274 278 <%text>## multiple patterns, to other issues server, wiki or others</%text>
275 279 <%text>## below an example how to create a wiki pattern</%text>
276 280 # wiki-some-id -> https://wiki.example.com/some-id
277 281
278 282 #issue_pat_wiki = (?:wiki-)(.+)
279 283 #issue_server_link_wiki = https://wiki.example.com/{id}
280 284 #issue_prefix_wiki = WIKI-
281 285
282 286 <%text>## alternative return HTTP header for failed authentication. Default HTTP</%text>
283 287 <%text>## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with</%text>
284 288 <%text>## handling that. Set this variable to 403 to return HTTPForbidden</%text>
285 289 auth_ret_code =
286 290
287 291 <%text>## locking return code. When repository is locked return this HTTP code. 2XX</%text>
288 292 <%text>## codes don't break the transactions while 4XX codes do</%text>
289 293 lock_ret_code = 423
290 294
291 295 <%text>## allows to change the repository location in settings page</%text>
292 296 allow_repo_location_change = True
293 297
294 298 <%text>## allows to setup custom hooks in settings page</%text>
295 299 allow_custom_hooks_settings = True
296 300
297 301 <%text>## extra extensions for indexing, space separated and without the leading '.'.</%text>
298 302 # index.extensions =
299 303 # gemfile
300 304 # lock
301 305
302 306 <%text>## extra filenames for indexing, space separated</%text>
303 307 # index.filenames =
304 308 # .dockerignore
305 309 # .editorconfig
306 310 # INSTALL
307 311 # CHANGELOG
308 312
309 313 <%text>####################################</%text>
310 314 <%text>### CELERY CONFIG ####</%text>
311 315 <%text>####################################</%text>
312 316
313 317 use_celery = false
314 318
315 319 <%text>## Example: connect to the virtual host 'rabbitmqhost' on localhost as rabbitmq:</%text>
316 320 broker.url = amqp://rabbitmq:qewqew@localhost:5672/rabbitmqhost
317 321
318 322 celery.imports = kallithea.lib.celerylib.tasks
319 323 celery.accept.content = pickle
320 324 celery.result.backend = amqp
321 325 celery.result.dburi = amqp://
322 326 celery.result.serialier = json
323 327
324 328 #celery.send.task.error.emails = true
325 329 #celery.amqp.task.result.expires = 18000
326 330
327 331 celeryd.concurrency = 2
328 332 celeryd.max.tasks.per.child = 1
329 333
330 334 <%text>## If true, tasks will never be sent to the queue, but executed locally instead.</%text>
331 335 celery.always.eager = false
332 336
333 337 <%text>####################################</%text>
334 338 <%text>### BEAKER CACHE ####</%text>
335 339 <%text>####################################</%text>
336 340
337 341 beaker.cache.data_dir = ${here}/data/cache/data
338 342 beaker.cache.lock_dir = ${here}/data/cache/lock
339 343
340 344 beaker.cache.regions = short_term,long_term,sql_cache_short
341 345
342 346 beaker.cache.short_term.type = memory
343 347 beaker.cache.short_term.expire = 60
344 348 beaker.cache.short_term.key_length = 256
345 349
346 350 beaker.cache.long_term.type = memory
347 351 beaker.cache.long_term.expire = 36000
348 352 beaker.cache.long_term.key_length = 256
349 353
350 354 beaker.cache.sql_cache_short.type = memory
351 355 beaker.cache.sql_cache_short.expire = 10
352 356 beaker.cache.sql_cache_short.key_length = 256
353 357
354 358 <%text>####################################</%text>
355 359 <%text>### BEAKER SESSION ####</%text>
356 360 <%text>####################################</%text>
357 361
358 362 <%text>## Name of session cookie. Should be unique for a given host and path, even when running</%text>
359 363 <%text>## on different ports. Otherwise, cookie sessions will be shared and messed up.</%text>
360 364 beaker.session.key = kallithea
361 365 <%text>## Sessions should always only be accessible by the browser, not directly by JavaScript.</%text>
362 366 beaker.session.httponly = true
363 367 <%text>## Session lifetime. 2592000 seconds is 30 days.</%text>
364 368 beaker.session.timeout = 2592000
365 369
366 370 <%text>## Server secret used with HMAC to ensure integrity of cookies.</%text>
367 371 beaker.session.secret = ${uuid()}
368 372 <%text>## Further, encrypt the data with AES.</%text>
369 373 #beaker.session.encrypt_key = <key_for_encryption>
370 374 #beaker.session.validate_key = <validation_key>
371 375
372 376 <%text>## Type of storage used for the session, current types are</%text>
373 377 <%text>## dbm, file, memcached, database, and memory.</%text>
374 378
375 379 <%text>## File system storage of session data. (default)</%text>
376 380 #beaker.session.type = file
377 381
378 382 <%text>## Cookie only, store all session data inside the cookie. Requires secure secrets.</%text>
379 383 #beaker.session.type = cookie
380 384
381 385 <%text>## Database storage of session data.</%text>
382 386 #beaker.session.type = ext:database
383 387 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/kallithea
384 388 #beaker.session.table_name = db_session
385 389
386 390 %if error_aggregation_service == 'appenlight':
387 391 <%text>############################</%text>
388 392 <%text>## ERROR HANDLING SYSTEMS ##</%text>
389 393 <%text>############################</%text>
390 394
391 395 <%text>####################</%text>
392 396 <%text>### [appenlight] ###</%text>
393 397 <%text>####################</%text>
394 398
395 399 <%text>## AppEnlight is tailored to work with Kallithea, see</%text>
396 400 <%text>## http://appenlight.com for details how to obtain an account</%text>
397 401 <%text>## you must install python package `appenlight_client` to make it work</%text>
398 402
399 403 <%text>## appenlight enabled</%text>
400 404 appenlight = false
401 405
402 406 appenlight.server_url = https://api.appenlight.com
403 407 appenlight.api_key = YOUR_API_KEY
404 408
405 409 <%text>## TWEAK AMOUNT OF INFO SENT HERE</%text>
406 410
407 411 <%text>## enables 404 error logging (default False)</%text>
408 412 appenlight.report_404 = false
409 413
410 414 <%text>## time in seconds after request is considered being slow (default 1)</%text>
411 415 appenlight.slow_request_time = 1
412 416
413 417 <%text>## record slow requests in application</%text>
414 418 <%text>## (needs to be enabled for slow datastore recording and time tracking)</%text>
415 419 appenlight.slow_requests = true
416 420
417 421 <%text>## enable hooking to application loggers</%text>
418 422 #appenlight.logging = true
419 423
420 424 <%text>## minimum log level for log capture</%text>
421 425 #appenlight.logging.level = WARNING
422 426
423 427 <%text>## send logs only from erroneous/slow requests</%text>
424 428 <%text>## (saves API quota for intensive logging)</%text>
425 429 appenlight.logging_on_error = false
426 430
427 431 <%text>## list of additional keywords that should be grabbed from environ object</%text>
428 432 <%text>## can be string with comma separated list of words in lowercase</%text>
429 433 <%text>## (by default client will always send following info:</%text>
430 434 <%text>## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that</%text>
431 435 <%text>## start with HTTP* this list be extended with additional keywords here</%text>
432 436 appenlight.environ_keys_whitelist =
433 437
434 438 <%text>## list of keywords that should be blanked from request object</%text>
435 439 <%text>## can be string with comma separated list of words in lowercase</%text>
436 440 <%text>## (by default client will always blank keys that contain following words</%text>
437 441 <%text>## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'</%text>
438 442 <%text>## this list be extended with additional keywords set here</%text>
439 443 appenlight.request_keys_blacklist =
440 444
441 445 <%text>## list of namespaces that should be ignores when gathering log entries</%text>
442 446 <%text>## can be string with comma separated list of namespaces</%text>
443 447 <%text>## (by default the client ignores own entries: appenlight_client.client)</%text>
444 448 appenlight.log_namespace_blacklist =
445 449
446 450 %elif error_aggregation_service == 'sentry':
447 451 <%text>################</%text>
448 452 <%text>### [sentry] ###</%text>
449 453 <%text>################</%text>
450 454
451 455 <%text>## sentry is a alternative open source error aggregator</%text>
452 456 <%text>## you must install python packages `sentry` and `raven` to enable</%text>
453 457
454 458 sentry.dsn = YOUR_DNS
455 459 sentry.servers =
456 460 sentry.name =
457 461 sentry.key =
458 462 sentry.public_key =
459 463 sentry.secret_key =
460 464 sentry.project =
461 465 sentry.site =
462 466 sentry.include_paths =
463 467 sentry.exclude_paths =
464 468
465 469 %endif
466 470 <%text>################################################################################</%text>
467 471 <%text>## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##</%text>
468 472 <%text>## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##</%text>
469 473 <%text>## execute malicious code after an exception is raised. ##</%text>
470 474 <%text>################################################################################</%text>
471 475 set debug = false
472 476
473 477 <%text>##################################</%text>
474 478 <%text>### LOGVIEW CONFIG ###</%text>
475 479 <%text>##################################</%text>
476 480
477 481 logview.sqlalchemy = #faa
478 482 logview.pylons.templating = #bfb
479 483 logview.pylons.util = #eee
480 484
481 485 <%text>#########################################################</%text>
482 486 <%text>### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###</%text>
483 487 <%text>#########################################################</%text>
484 488
485 489 %if database_engine == 'sqlite':
486 490 # SQLITE [default]
487 491 sqlalchemy.url = sqlite:///${here}/kallithea.db?timeout=60
488 492
489 493 %elif database_engine == 'postgres':
490 494 # POSTGRESQL
491 495 sqlalchemy.url = postgresql://user:pass@localhost/kallithea
492 496
493 497 %elif database_engine == 'mysql':
494 498 # MySQL
495 499 sqlalchemy.url = mysql://user:pass@localhost/kallithea?charset=utf8
496 500
497 501 %endif
498 502 # see sqlalchemy docs for others
499 503
500 504 sqlalchemy.echo = false
501 505 sqlalchemy.pool_recycle = 3600
502 506
503 507 <%text>################################</%text>
504 508 <%text>### ALEMBIC CONFIGURATION ####</%text>
505 509 <%text>################################</%text>
506 510
507 511 [alembic]
508 512 script_location = kallithea:alembic
509 513
510 514 <%text>################################</%text>
511 515 <%text>### LOGGING CONFIGURATION ####</%text>
512 516 <%text>################################</%text>
513 517
514 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 521 [handlers]
518 522 keys = console, console_sql
519 523
520 524 [formatters]
521 525 keys = generic, color_formatter, color_formatter_sql
522 526
523 527 <%text>#############</%text>
524 528 <%text>## LOGGERS ##</%text>
525 529 <%text>#############</%text>
526 530
527 531 [logger_root]
528 532 level = NOTSET
529 533 handlers = console
530 534
531 535 [logger_routes]
532 536 level = DEBUG
533 537 handlers =
534 538 qualname = routes.middleware
535 539 <%text>## "level = DEBUG" logs the route matched and routing variables.</%text>
536 540 propagate = 1
537 541
538 542 [logger_beaker]
539 543 level = DEBUG
540 544 handlers =
541 545 qualname = beaker.container
542 546 propagate = 1
543 547
544 548 [logger_templates]
545 549 level = INFO
546 550 handlers =
547 551 qualname = pylons.templating
548 552 propagate = 1
549 553
550 554 [logger_kallithea]
551 555 level = DEBUG
552 556 handlers =
553 557 qualname = kallithea
554 558 propagate = 1
555 559
560 [logger_gearbox]
561 level = DEBUG
562 handlers =
563 qualname = gearbox
564 propagate = 1
565
556 566 [logger_sqlalchemy]
557 567 level = INFO
558 568 handlers = console_sql
559 569 qualname = sqlalchemy.engine
560 570 propagate = 0
561 571
562 572 [logger_whoosh_indexer]
563 573 level = DEBUG
564 574 handlers =
565 575 qualname = whoosh_indexer
566 576 propagate = 1
567 577
568 578 <%text>##############</%text>
569 579 <%text>## HANDLERS ##</%text>
570 580 <%text>##############</%text>
571 581
572 582 [handler_console]
573 583 class = StreamHandler
574 584 args = (sys.stderr,)
575 585 level = INFO
576 586 formatter = generic
577 587
578 588 [handler_console_sql]
579 589 class = StreamHandler
580 590 args = (sys.stderr,)
581 591 level = WARN
582 592 formatter = generic
583 593
584 594 <%text>################</%text>
585 595 <%text>## FORMATTERS ##</%text>
586 596 <%text>################</%text>
587 597
588 598 [formatter_generic]
589 599 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
590 600 datefmt = %Y-%m-%d %H:%M:%S
591 601
592 602 [formatter_color_formatter]
593 603 class = kallithea.lib.colored_formatter.ColorFormatter
594 604 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
595 605 datefmt = %Y-%m-%d %H:%M:%S
596 606
597 607 [formatter_color_formatter_sql]
598 608 class = kallithea.lib.colored_formatter.ColorFormatterSql
599 609 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
600 610 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,589 +1,598 b''
1 1 ################################################################################
2 2 ################################################################################
3 3 # Kallithea - Example config #
4 4 # #
5 5 # The %(here)s variable will be replaced with the parent directory of this file#
6 6 ################################################################################
7 7 ################################################################################
8 8
9 9 [DEFAULT]
10 10 debug = true
11 11 pdebug = false
12 12
13 13 ################################################################################
14 14 ## Email settings ##
15 15 ## ##
16 16 ## Refer to the documentation ("Email settings") for more details. ##
17 17 ## ##
18 18 ## It is recommended to use a valid sender address that passes access ##
19 19 ## validation and spam filtering in mail servers. ##
20 20 ################################################################################
21 21
22 22 ## 'From' header for application emails. You can optionally add a name.
23 23 ## Default:
24 24 #app_email_from = Kallithea
25 25 ## Examples:
26 26 #app_email_from = Kallithea <kallithea-noreply@example.com>
27 27 #app_email_from = kallithea-noreply@example.com
28 28
29 29 ## Subject prefix for application emails.
30 30 ## A space between this prefix and the real subject is automatically added.
31 31 ## Default:
32 32 #email_prefix =
33 33 ## Example:
34 34 #email_prefix = [Kallithea]
35 35
36 36 ## Recipients for error emails and fallback recipients of application mails.
37 37 ## Multiple addresses can be specified, space-separated.
38 38 ## Only addresses are allowed, do not add any name part.
39 39 ## Default:
40 40 #email_to =
41 41 ## Examples:
42 42 #email_to = admin@example.com
43 43 #email_to = admin@example.com another_admin@example.com
44 44
45 45 ## 'From' header for error emails. You can optionally add a name.
46 46 ## Default:
47 47 #error_email_from = pylons@yourapp.com
48 48 ## Examples:
49 49 #error_email_from = Kallithea Errors <kallithea-noreply@example.com>
50 50 #error_email_from = paste_error@example.com
51 51
52 52 ## SMTP server settings
53 53 ## If specifying credentials, make sure to use secure connections.
54 54 ## Default: Send unencrypted unauthenticated mails to the specified smtp_server.
55 55 ## For "SSL", use smtp_use_ssl = true and smtp_port = 465.
56 56 ## For "STARTTLS", use smtp_use_tls = true and smtp_port = 587.
57 57 #smtp_server = smtp.example.com
58 58 #smtp_username =
59 59 #smtp_password =
60 60 #smtp_port = 25
61 61 #smtp_use_ssl = false
62 62 #smtp_use_tls = false
63 63
64 64 [server:main]
65 ## PASTE ##
66 #use = egg:Paste#http
65 ## Gearbox default web server ##
66 #use = egg:gearbox#wsgiref
67 67 ## nr of worker threads to spawn
68 68 #threadpool_workers = 1
69 69 ## max request before thread respawn
70 70 #threadpool_max_requests = 100
71 71 ## option to use threads of process
72 72 #use_threadpool = true
73 73
74 ## Gearbox gevent web server ##
75 #use = egg:gearbox#gevent
76
74 77 ## WAITRESS ##
75 78 use = egg:waitress#main
76 79 ## number of worker threads
77 80 threads = 1
78 81 ## MAX BODY SIZE 100GB
79 82 max_request_body_size = 107374182400
80 83 ## use poll instead of select, fixes fd limits, may not work on old
81 84 ## windows systems.
82 85 #asyncore_use_poll = True
83 86
84 87 ## GUNICORN ##
85 88 #use = egg:gunicorn#main
86 89 ## number of process workers. You must set `instance_id = *` when this option
87 90 ## is set to more than one worker
88 91 #workers = 1
89 92 ## process name
90 93 #proc_name = kallithea
91 94 ## type of worker class, one of sync, eventlet, gevent, tornado
92 95 ## recommended for bigger setup is using of of other than sync one
93 96 #worker_class = sync
94 97 #max_requests = 1000
95 98 ## amount of time a worker can handle request before it gets killed and
96 99 ## restarted
97 100 #timeout = 3600
98 101
99 102 ## UWSGI ##
100 103 ## run with uwsgi --ini-paste-logged <inifile.ini>
101 104 #[uwsgi]
102 105 #socket = /tmp/uwsgi.sock
103 106 #master = true
104 107 #http = 127.0.0.1:5000
105 108
106 109 ## set as deamon and redirect all output to file
107 110 #daemonize = ./uwsgi_kallithea.log
108 111
109 112 ## master process PID
110 113 #pidfile = ./uwsgi_kallithea.pid
111 114
112 115 ## stats server with workers statistics, use uwsgitop
113 116 ## for monitoring, `uwsgitop 127.0.0.1:1717`
114 117 #stats = 127.0.0.1:1717
115 118 #memory-report = true
116 119
117 120 ## log 5XX errors
118 121 #log-5xx = true
119 122
120 123 ## Set the socket listen queue size.
121 124 #listen = 256
122 125
123 126 ## Gracefully Reload workers after the specified amount of managed requests
124 127 ## (avoid memory leaks).
125 128 #max-requests = 1000
126 129
127 130 ## enable large buffers
128 131 #buffer-size = 65535
129 132
130 133 ## socket and http timeouts ##
131 134 #http-timeout = 3600
132 135 #socket-timeout = 3600
133 136
134 137 ## Log requests slower than the specified number of milliseconds.
135 138 #log-slow = 10
136 139
137 140 ## Exit if no app can be loaded.
138 141 #need-app = true
139 142
140 143 ## Set lazy mode (load apps in workers instead of master).
141 144 #lazy = true
142 145
143 146 ## scaling ##
144 147 ## set cheaper algorithm to use, if not set default will be used
145 148 #cheaper-algo = spare
146 149
147 150 ## minimum number of workers to keep at all times
148 151 #cheaper = 1
149 152
150 153 ## number of workers to spawn at startup
151 154 #cheaper-initial = 1
152 155
153 156 ## maximum number of workers that can be spawned
154 157 #workers = 4
155 158
156 159 ## how many workers should be spawned at a time
157 160 #cheaper-step = 1
158 161
159 162 ## COMMON ##
160 163 host = 127.0.0.1
161 164 port = 5000
162 165
163 166 ## middleware for hosting the WSGI application under a URL prefix
164 167 #[filter:proxy-prefix]
165 168 #use = egg:PasteDeploy#prefix
166 169 #prefix = /<your-prefix>
167 170
168 171 [app:main]
169 172 use = egg:kallithea
170 173 ## enable proxy prefix middleware
171 174 #filter-with = proxy-prefix
172 175
173 176 full_stack = true
174 177 static_files = true
175 178 ## Available Languages:
176 179 ## cs de fr hu ja nl_BE pl pt_BR ru sk zh_CN zh_TW
177 180 lang =
178 181 cache_dir = %(here)s/data
179 182 index_dir = %(here)s/data/index
180 183
181 184 ## perform a full repository scan on each server start, this should be
182 185 ## set to false after first startup, to allow faster server restarts.
183 186 initial_repo_scan = false
184 187
185 188 ## uncomment and set this path to use archive download cache
186 189 archive_cache_dir = %(here)s/tarballcache
187 190
188 191 ## change this to unique ID for security
189 192 app_instance_uuid = ${app_instance_uuid}
190 193
191 194 ## cut off limit for large diffs (size in bytes)
192 195 cut_off_limit = 256000
193 196
194 197 ## force https in Kallithea, fixes https redirects, assumes it's always https
195 198 force_https = false
196 199
197 200 ## use Strict-Transport-Security headers
198 201 use_htsts = false
199 202
200 203 ## number of commits stats will parse on each iteration
201 204 commit_parse_limit = 25
202 205
203 206 ## path to git executable
204 207 git_path = git
205 208
206 209 ## git rev filter option, --all is the default filter, if you need to
207 210 ## hide all refs in changelog switch this to --branches --tags
208 211 #git_rev_filter = --branches --tags
209 212
210 213 ## RSS feed options
211 214 rss_cut_off_limit = 256000
212 215 rss_items_per_page = 10
213 216 rss_include_diff = false
214 217
215 218 ## options for showing and identifying changesets
216 219 show_sha_length = 12
217 220 show_revision_number = false
218 221
219 222 ## Canonical URL to use when creating full URLs in UI and texts.
220 223 ## Useful when the site is available under different names or protocols.
221 224 ## Defaults to what is provided in the WSGI environment.
222 225 #canonical_url = https://kallithea.example.com/repos
223 226
224 227 ## gist URL alias, used to create nicer urls for gist. This should be an
225 228 ## url that does rewrites to _admin/gists/<gistid>.
226 229 ## example: http://gist.example.com/{gistid}. Empty means use the internal
227 230 ## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid>
228 231 gist_alias_url =
229 232
230 233 ## white list of API enabled controllers. This allows to add list of
231 234 ## controllers to which access will be enabled by api_key. eg: to enable
232 235 ## api access to raw_files put `FilesController:raw`, to enable access to patches
233 236 ## add `ChangesetController:changeset_patch`. This list should be "," separated
234 237 ## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
235 238 ## Recommended settings below are commented out:
236 239 api_access_controllers_whitelist =
237 240 # ChangesetController:changeset_patch,
238 241 # ChangesetController:changeset_raw,
239 242 # FilesController:raw,
240 243 # FilesController:archivefile
241 244
242 245 ## default encoding used to convert from and to unicode
243 246 ## can be also a comma separated list of encoding in case of mixed encodings
244 247 default_encoding = utf8
245 248
246 249 ## issue tracker for Kallithea (leave blank to disable, absent for default)
247 250 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
248 251
249 252 ## issue tracking mapping for commits messages
250 253 ## comment out issue_pat, issue_server, issue_prefix to enable
251 254
252 255 ## pattern to get the issues from commit messages
253 256 ## default one used here is #<numbers> with a regex passive group for `#`
254 257 ## {id} will be all groups matched from this pattern
255 258
256 259 issue_pat = (?:\s*#)(\d+)
257 260
258 261 ## server url to the issue, each {id} will be replaced with match
259 262 ## fetched from the regex and {repo} is replaced with full repository name
260 263 ## including groups {repo_name} is replaced with just name of repo
261 264
262 265 issue_server_link = https://issues.example.com/{repo}/issue/{id}
263 266
264 267 ## prefix to add to link to indicate it's an url
265 268 ## #314 will be replaced by <issue_prefix><id>
266 269
267 270 issue_prefix = #
268 271
269 272 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
270 273 ## multiple patterns, to other issues server, wiki or others
271 274 ## below an example how to create a wiki pattern
272 275 # wiki-some-id -> https://wiki.example.com/some-id
273 276
274 277 #issue_pat_wiki = (?:wiki-)(.+)
275 278 #issue_server_link_wiki = https://wiki.example.com/{id}
276 279 #issue_prefix_wiki = WIKI-
277 280
278 281 ## alternative return HTTP header for failed authentication. Default HTTP
279 282 ## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
280 283 ## handling that. Set this variable to 403 to return HTTPForbidden
281 284 auth_ret_code =
282 285
283 286 ## locking return code. When repository is locked return this HTTP code. 2XX
284 287 ## codes don't break the transactions while 4XX codes do
285 288 lock_ret_code = 423
286 289
287 290 ## allows to change the repository location in settings page
288 291 allow_repo_location_change = True
289 292
290 293 ## allows to setup custom hooks in settings page
291 294 allow_custom_hooks_settings = True
292 295
293 296 ## extra extensions for indexing, space separated and without the leading '.'.
294 297 # index.extensions =
295 298 # gemfile
296 299 # lock
297 300
298 301 ## extra filenames for indexing, space separated
299 302 # index.filenames =
300 303 # .dockerignore
301 304 # .editorconfig
302 305 # INSTALL
303 306 # CHANGELOG
304 307
305 308 ####################################
306 309 ### CELERY CONFIG ####
307 310 ####################################
308 311
309 312 use_celery = false
310 313
311 314 ## Example: connect to the virtual host 'rabbitmqhost' on localhost as rabbitmq:
312 315 broker.url = amqp://rabbitmq:qewqew@localhost:5672/rabbitmqhost
313 316
314 317 celery.imports = kallithea.lib.celerylib.tasks
315 318 celery.accept.content = pickle
316 319 celery.result.backend = amqp
317 320 celery.result.dburi = amqp://
318 321 celery.result.serialier = json
319 322
320 323 #celery.send.task.error.emails = true
321 324 #celery.amqp.task.result.expires = 18000
322 325
323 326 celeryd.concurrency = 2
324 327 celeryd.max.tasks.per.child = 1
325 328
326 329 ## If true, tasks will never be sent to the queue, but executed locally instead.
327 330 celery.always.eager = false
328 331
329 332 ####################################
330 333 ### BEAKER CACHE ####
331 334 ####################################
332 335
333 336 beaker.cache.data_dir = %(here)s/data/cache/data
334 337 beaker.cache.lock_dir = %(here)s/data/cache/lock
335 338
336 339 beaker.cache.regions = short_term,long_term,sql_cache_short
337 340
338 341 beaker.cache.short_term.type = memory
339 342 beaker.cache.short_term.expire = 60
340 343 beaker.cache.short_term.key_length = 256
341 344
342 345 beaker.cache.long_term.type = memory
343 346 beaker.cache.long_term.expire = 36000
344 347 beaker.cache.long_term.key_length = 256
345 348
346 349 beaker.cache.sql_cache_short.type = memory
347 350 beaker.cache.sql_cache_short.expire = 10
348 351 beaker.cache.sql_cache_short.key_length = 256
349 352
350 353 ####################################
351 354 ### BEAKER SESSION ####
352 355 ####################################
353 356
354 357 ## Name of session cookie. Should be unique for a given host and path, even when running
355 358 ## on different ports. Otherwise, cookie sessions will be shared and messed up.
356 359 beaker.session.key = kallithea
357 360 ## Sessions should always only be accessible by the browser, not directly by JavaScript.
358 361 beaker.session.httponly = true
359 362 ## Session lifetime. 2592000 seconds is 30 days.
360 363 beaker.session.timeout = 2592000
361 364
362 365 ## Server secret used with HMAC to ensure integrity of cookies.
363 366 beaker.session.secret = ${app_instance_uuid}
364 367 ## Further, encrypt the data with AES.
365 368 #beaker.session.encrypt_key = <key_for_encryption>
366 369 #beaker.session.validate_key = <validation_key>
367 370
368 371 ## Type of storage used for the session, current types are
369 372 ## dbm, file, memcached, database, and memory.
370 373
371 374 ## File system storage of session data. (default)
372 375 #beaker.session.type = file
373 376
374 377 ## Cookie only, store all session data inside the cookie. Requires secure secrets.
375 378 #beaker.session.type = cookie
376 379
377 380 ## Database storage of session data.
378 381 #beaker.session.type = ext:database
379 382 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/kallithea
380 383 #beaker.session.table_name = db_session
381 384
382 385 ############################
383 386 ## ERROR HANDLING SYSTEMS ##
384 387 ############################
385 388
386 389 ####################
387 390 ### [appenlight] ###
388 391 ####################
389 392
390 393 ## AppEnlight is tailored to work with Kallithea, see
391 394 ## http://appenlight.com for details how to obtain an account
392 395 ## you must install python package `appenlight_client` to make it work
393 396
394 397 ## appenlight enabled
395 398 appenlight = false
396 399
397 400 appenlight.server_url = https://api.appenlight.com
398 401 appenlight.api_key = YOUR_API_KEY
399 402
400 403 ## TWEAK AMOUNT OF INFO SENT HERE
401 404
402 405 ## enables 404 error logging (default False)
403 406 appenlight.report_404 = false
404 407
405 408 ## time in seconds after request is considered being slow (default 1)
406 409 appenlight.slow_request_time = 1
407 410
408 411 ## record slow requests in application
409 412 ## (needs to be enabled for slow datastore recording and time tracking)
410 413 appenlight.slow_requests = true
411 414
412 415 ## enable hooking to application loggers
413 416 #appenlight.logging = true
414 417
415 418 ## minimum log level for log capture
416 419 #appenlight.logging.level = WARNING
417 420
418 421 ## send logs only from erroneous/slow requests
419 422 ## (saves API quota for intensive logging)
420 423 appenlight.logging_on_error = false
421 424
422 425 ## list of additional keywords that should be grabbed from environ object
423 426 ## can be string with comma separated list of words in lowercase
424 427 ## (by default client will always send following info:
425 428 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
426 429 ## start with HTTP* this list be extended with additional keywords here
427 430 appenlight.environ_keys_whitelist =
428 431
429 432 ## list of keywords that should be blanked from request object
430 433 ## can be string with comma separated list of words in lowercase
431 434 ## (by default client will always blank keys that contain following words
432 435 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
433 436 ## this list be extended with additional keywords set here
434 437 appenlight.request_keys_blacklist =
435 438
436 439 ## list of namespaces that should be ignores when gathering log entries
437 440 ## can be string with comma separated list of namespaces
438 441 ## (by default the client ignores own entries: appenlight_client.client)
439 442 appenlight.log_namespace_blacklist =
440 443
441 444 ################
442 445 ### [sentry] ###
443 446 ################
444 447
445 448 ## sentry is a alternative open source error aggregator
446 449 ## you must install python packages `sentry` and `raven` to enable
447 450
448 451 sentry.dsn = YOUR_DNS
449 452 sentry.servers =
450 453 sentry.name =
451 454 sentry.key =
452 455 sentry.public_key =
453 456 sentry.secret_key =
454 457 sentry.project =
455 458 sentry.site =
456 459 sentry.include_paths =
457 460 sentry.exclude_paths =
458 461
459 462 ################################################################################
460 463 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
461 464 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
462 465 ## execute malicious code after an exception is raised. ##
463 466 ################################################################################
464 467 set debug = false
465 468
466 469 ##################################
467 470 ### LOGVIEW CONFIG ###
468 471 ##################################
469 472
470 473 logview.sqlalchemy = #faa
471 474 logview.pylons.templating = #bfb
472 475 logview.pylons.util = #eee
473 476
474 477 #########################################################
475 478 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
476 479 #########################################################
477 480
478 481 # SQLITE [default]
479 482 sqlalchemy.url = sqlite:///%(here)s/kallithea.db?timeout=60
480 483
481 484 # POSTGRESQL
482 485 #sqlalchemy.url = postgresql://user:pass@localhost/kallithea
483 486
484 487 # MySQL
485 488 #sqlalchemy.url = mysql://user:pass@localhost/kallithea?charset=utf8
486 489
487 490 # see sqlalchemy docs for others
488 491
489 492 sqlalchemy.echo = false
490 493 sqlalchemy.pool_recycle = 3600
491 494
492 495 ################################
493 496 ### ALEMBIC CONFIGURATION ####
494 497 ################################
495 498
496 499 [alembic]
497 500 script_location = kallithea:alembic
498 501
499 502 ################################
500 503 ### LOGGING CONFIGURATION ####
501 504 ################################
502 505
503 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 509 [handlers]
507 510 keys = console, console_sql
508 511
509 512 [formatters]
510 513 keys = generic, color_formatter, color_formatter_sql
511 514
512 515 #############
513 516 ## LOGGERS ##
514 517 #############
515 518
516 519 [logger_root]
517 520 level = NOTSET
518 521 handlers = console
519 522
520 523 [logger_routes]
521 524 level = DEBUG
522 525 handlers =
523 526 qualname = routes.middleware
524 527 ## "level = DEBUG" logs the route matched and routing variables.
525 528 propagate = 1
526 529
527 530 [logger_beaker]
528 531 level = DEBUG
529 532 handlers =
530 533 qualname = beaker.container
531 534 propagate = 1
532 535
533 536 [logger_templates]
534 537 level = INFO
535 538 handlers =
536 539 qualname = pylons.templating
537 540 propagate = 1
538 541
539 542 [logger_kallithea]
540 543 level = DEBUG
541 544 handlers =
542 545 qualname = kallithea
543 546 propagate = 1
544 547
548 [logger_gearbox]
549 level = DEBUG
550 handlers =
551 qualname = gearbox
552 propagate = 1
553
545 554 [logger_sqlalchemy]
546 555 level = INFO
547 556 handlers = console_sql
548 557 qualname = sqlalchemy.engine
549 558 propagate = 0
550 559
551 560 [logger_whoosh_indexer]
552 561 level = DEBUG
553 562 handlers =
554 563 qualname = whoosh_indexer
555 564 propagate = 1
556 565
557 566 ##############
558 567 ## HANDLERS ##
559 568 ##############
560 569
561 570 [handler_console]
562 571 class = StreamHandler
563 572 args = (sys.stderr,)
564 573 level = INFO
565 574 formatter = generic
566 575
567 576 [handler_console_sql]
568 577 class = StreamHandler
569 578 args = (sys.stderr,)
570 579 level = WARN
571 580 formatter = generic
572 581
573 582 ################
574 583 ## FORMATTERS ##
575 584 ################
576 585
577 586 [formatter_generic]
578 587 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
579 588 datefmt = %Y-%m-%d %H:%M:%S
580 589
581 590 [formatter_color_formatter]
582 591 class = kallithea.lib.colored_formatter.ColorFormatter
583 592 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
584 593 datefmt = %Y-%m-%d %H:%M:%S
585 594
586 595 [formatter_color_formatter_sql]
587 596 class = kallithea.lib.colored_formatter.ColorFormatterSql
588 597 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
589 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 3 class UpgradeDb(Command):
4 hidden = True
5 summary = '(removed)'
4 '''(removed)'''
5
6 deprecated = True
6 7
7 8 def run(self, args):
8 9 raise SystemExit(
9 10 'The "paster upgrade-db" command has been removed; please see the docs:\n'
10 11 ' https://kallithea.readthedocs.io/en/default/upgrade.html'
11 12 )
@@ -1,79 +1,72 b''
1 1 # -*- coding: utf-8 -*-
2 2 # This program is free software: you can redistribute it and/or modify
3 3 # it under the terms of the GNU General Public License as published by
4 4 # the Free Software Foundation, either version 3 of the License, or
5 5 # (at your option) any later version.
6 6 #
7 7 # This program is distributed in the hope that it will be useful,
8 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 # GNU General Public License for more details.
11 11 #
12 12 # You should have received a copy of the GNU General Public License
13 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 """
15 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 21 This file was forked by the Kallithea project in July 2014.
22 22 Original author and date, and relevant copyright and licensing information is below:
23 23 :created_on: mar 27, 2013
24 24 :author: marcink
25 25 :copyright: (c) 2013 RhodeCode GmbH, and others.
26 26 :license: GPLv3, see LICENSE.md for more details.
27 27 """
28 28
29 29
30 30 import os
31 31 import sys
32 32
33 33 from kallithea.lib.paster_commands.common import BasePasterCommand
34 34 from kallithea.model.meta import Session
35 35 from kallithea.lib.utils2 import safe_str
36 36 from kallithea.model.db import CacheInvalidation
37 37
38 38
39 39 class Command(BasePasterCommand):
40
41 max_args = 1
42 min_args = 1
40 "Kallithea: Utilities for managing caching of database content"
43 41
44 usage = "CONFIG_FILE"
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
42 def take_action(self, args):
54 43 _caches = CacheInvalidation.query().order_by(CacheInvalidation.cache_key).all()
55 if self.options.show:
44 if args.show:
56 45 for c_obj in _caches:
57 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 48 for c_obj in _caches:
60 49 Session().delete(c_obj)
61 50 print 'Removing key: %s' % (safe_str(c_obj.cache_key))
62 51 Session().commit()
63 52 else:
64 53 print 'Nothing done, exiting...'
65 54
66 def update_parser(self):
67 self.parser.add_option(
55 def get_parser(self, prog_name):
56 parser = super(Command, self).get_parser(prog_name)
57
58 parser.add_argument(
68 59 '--show',
69 60 action='store_true',
70 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 66 '--cleanup',
76 67 action="store_true",
77 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 1 # -*- coding: utf-8 -*-
2 2
3 import argparse
4
3 5 import kallithea
4 6 from kallithea.lib.paster_commands.common import BasePasterCommand
5 7 from kallithea.lib.utils import load_rcextensions
6 8 from kallithea.lib.utils2 import str2bool
7 9
8 10 __all__ = ['Command']
9 11
10 12
11 13 class Command(BasePasterCommand):
12 """Start the celery worker
13
14 Starts the celery worker that uses a paste.deploy configuration
15 file.
16 """
14 """Kallithea: Celery worker for asynchronous tasks"""
17 15
18 usage = 'CONFIG_FILE [celeryd options...]'
19 summary = __doc__.splitlines()[0]
20 description = "".join(__doc__.splitlines()[2:])
21 group_name = "Kallithea"
22
23 parser = BasePasterCommand.standard_parser(quiet=True)
16 # Starts the celery worker using configuration from a paste.deploy
17 # configuration file.
24 18
25 def update_parser(self):
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)
19 requires_db_session = False # will start session on demand
30 20
31 def command(self):
21 def take_action(self, args):
32 22 from kallithea.lib import celerypylons
33 23 from tg import config
34 24 try:
35 25 CELERY_ON = str2bool(config['app_conf'].get('use_celery'))
36 26 except KeyError:
37 27 CELERY_ON = False
38 28
39 29 if not CELERY_ON:
40 30 raise Exception('Please set use_celery = true in .ini config '
41 31 'file before running celeryd')
42 32 kallithea.CELERY_ON = CELERY_ON
43 33
44 34 load_rcextensions(config['here'])
45 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 1 # -*- coding: utf-8 -*-
2 2 # This program is free software: you can redistribute it and/or modify
3 3 # it under the terms of the GNU General Public License as published by
4 4 # the Free Software Foundation, either version 3 of the License, or
5 5 # (at your option) any later version.
6 6 #
7 7 # This program is distributed in the hope that it will be useful,
8 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 # GNU General Public License for more details.
11 11 #
12 12 # You should have received a copy of the GNU General Public License
13 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 """
15 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 21 This file was forked by the Kallithea project in July 2014.
22 22 Original author and date, and relevant copyright and licensing information is below:
23 23 :created_on: Jul 14, 2012
24 24 :author: marcink
25 25 :copyright: (c) 2013 RhodeCode GmbH, and others.
26 26 :license: GPLv3, see LICENSE.md for more details.
27 27 """
28 28
29 29
30 30 import os
31 31 import sys
32 32 import re
33 33 import shutil
34 34 import datetime
35 35
36 36 from kallithea.lib.paster_commands.common import ask_ok, BasePasterCommand
37 37 from kallithea.lib.utils import REMOVED_REPO_PAT
38 38 from kallithea.lib.utils2 import safe_str
39 39 from kallithea.model.db import Ui
40 40
41 41
42 42 class Command(BasePasterCommand):
43
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"
43 """Kallithea: Cleanup of backup files of deleted repositories"""
52 44
53 45 def _parse_older_than(self, val):
54 46 regex = re.compile(r'((?P<days>\d+?)d)?((?P<hours>\d+?)h)?((?P<minutes>\d+?)m)?((?P<seconds>\d+?)s)?')
55 47 parts = regex.match(val)
56 48 if not parts:
57 49 return
58 50 parts = parts.groupdict()
59 51 time_params = {}
60 52 for (name, param) in parts.iteritems():
61 53 if param:
62 54 time_params[name] = int(param)
63 55 return datetime.timedelta(**time_params)
64 56
65 57 def _extract_date(self, name):
66 58 """
67 59 Extract the date part from rm__<date> pattern of removed repos,
68 60 and convert it to datetime object
69 61
70 62 :param name:
71 63 """
72 64 date_part = name[4:19] # 4:19 since we don't parse milliseconds
73 65 return datetime.datetime.strptime(date_part, '%Y%m%d_%H%M%S')
74 66
75 def command(self):
76 #get SqlAlchemy session
77 self._init_session()
78
67 def take_action(self, args):
79 68 repos_location = Ui.get_repos_location()
80 69 to_remove = []
81 70 for dn_, dirs, f in os.walk(safe_str(repos_location)):
82 71 alldirs = list(dirs)
83 72 del dirs[:]
84 73 if ('.hg' in alldirs or
85 74 '.git' in alldirs or
86 75 '.svn' in alldirs or
87 76 'objects' in alldirs and ('refs' in alldirs or 'packed-refs' in f)):
88 77 continue
89 78 for loc in alldirs:
90 79 if REMOVED_REPO_PAT.match(loc):
91 80 to_remove.append([os.path.join(dn_, loc),
92 81 self._extract_date(loc)])
93 82 else:
94 83 dirs.append(loc)
95 84 if dirs:
96 85 print 'Scanning: %s' % dn_
97 86
98 87 #filter older than (if present)!
99 88 now = datetime.datetime.now()
100 older_than = self.options.older_than
89 older_than = args.older_than
101 90 if older_than:
102 91 to_remove_filtered = []
103 92 older_than_date = self._parse_older_than(older_than)
104 93 for name, date_ in to_remove:
105 94 repo_age = now - date_
106 95 if repo_age > older_than_date:
107 96 to_remove_filtered.append([name, date_])
108 97
109 98 to_remove = to_remove_filtered
110 99 print 'Removing %s deleted repos older than %s (%s)' \
111 100 % (len(to_remove), older_than, older_than_date)
112 101 else:
113 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 104 # don't ask just remove !
116 105 remove = True
117 106 else:
118 107 remove = ask_ok('the following repositories will be deleted completely:\n%s\n'
119 108 'are you sure you want to remove them [y/n]?'
120 109 % '\n'.join(['%s removed on %s' % (safe_str(x[0]), safe_str(x[1]))
121 110 for x in to_remove]))
122 111
123 112 if remove:
124 113 for path, date_ in to_remove:
125 114 print 'Removing repository %s' % path
126 115 shutil.rmtree(path)
127 116 else:
128 117 print 'Nothing done, exiting...'
129 118
130 def update_parser(self):
131 self.parser.add_option(
119 def get_parser(self, prog_name):
120 parser = super(Command, self).get_parser(prog_name)
121
122 parser.add_argument(
132 123 '--older-than',
133 124 action='store',
134 125 dest='older_than',
135 126 help=("only remove repos that have been removed "
136 127 "at least given time ago. "
137 128 "The default is to remove all removed repositories. "
138 129 "Possible suffixes: "
139 130 "d (days), h (hours), m (minutes), s (seconds). "
140 131 "For example --older-than=30d deletes repositories "
141 132 "removed more than 30 days ago.")
142 133 )
143 134
144 self.parser.add_option(
135 parser.add_argument(
145 136 '--dont-ask',
146 137 action="store_true",
147 138 dest="dont_ask",
148 139 help="remove repositories without asking for confirmation."
149 140 )
141
142 return parser
@@ -1,107 +1,108 b''
1 1 # -*- coding: utf-8 -*-
2 2 # This program is free software: you can redistribute it and/or modify
3 3 # it under the terms of the GNU General Public License as published by
4 4 # the Free Software Foundation, either version 3 of the License, or
5 5 # (at your option) any later version.
6 6 #
7 7 # This program is distributed in the hope that it will be useful,
8 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 # GNU General Public License for more details.
11 11 #
12 12 # You should have received a copy of the GNU General Public License
13 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 """
15 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 20 This file was forked by the Kallithea project in July 2014.
21 21 Original author and date, and relevant copyright and licensing information is below:
22 22 :created_on: Apr 18, 2010
23 23 :author: marcink
24 24 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 25 :license: GPLv3, see LICENSE.md for more details.
26 26 """
27 27
28 28 import os
29 import logging
29 import sys
30 import logging.config
30 31
31 import paste
32 from paste.script.command import Command, BadCommand
33
34 from kallithea.lib.utils import setup_cache_regions
32 import paste.deploy
33 import gearbox.command
35 34
36 35
37 36 def ask_ok(prompt, retries=4, complaint='Yes or no please!'):
38 37 while True:
39 38 ok = raw_input(prompt)
40 39 if ok in ('y', 'ye', 'yes'):
41 40 return True
42 41 if ok in ('n', 'no', 'nop', 'nope'):
43 42 return False
44 43 retries = retries - 1
45 44 if retries < 0:
46 45 raise IOError
47 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
55 min_args_error = "Please provide a paster config file as an argument."
56 takes_config_file = 1
57 requires_config_file = True
53
54 # override to control how much get_parser and run should do:
55 takes_config_file = True
56 requires_db_session = True
58 57
59 58 def run(self, args):
60 59 """
61 60 Overrides Command.run
62 61
63 62 Checks for a config file argument and loads it.
64 63 """
65 if len(args) < self.min_args:
66 raise BadCommand(
67 self.min_args_error % {'min_args': self.min_args,
68 'actual_args': len(args)})
64 if self.takes_config_file:
65 self._bootstrap_config(args.config_file)
66 if self.requires_db_session:
67 self._init_session()
69 68
70 # Decrement because we're going to lob off the first argument.
71 # @@ This is hacky
72 self.min_args -= 1
73 self.bootstrap_config(args[0])
74 self.update_parser()
75 return super(BasePasterCommand, self).run(args[1:])
69 return super(BasePasterCommand, self).run(args)
70
71 def get_parser(self, prog_name):
72 parser = super(BasePasterCommand, self).get_parser(prog_name)
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
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.
83 Read the config file and initialize logging and the application.
89 84 """
90 85 from tg import config as pylonsconfig
91 86
92 self.path_to_ini_file = os.path.realpath(conf)
93 conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
87 path_to_ini_file = os.path.realpath(config_file)
88 conf = paste.deploy.appconfig('config:' + path_to_ini_file)
89 logging.config.fileConfig(path_to_ini_file)
94 90 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
95 91
96 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 97 from tg import config
103 98 from kallithea.model.base import init_model
104 99 from kallithea.lib.utils2 import engine_from_config
100 from kallithea.lib.utils import setup_cache_regions
105 101 setup_cache_regions(config)
106 102 engine = engine_from_config(config, 'sqlalchemy.')
107 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 1 # -*- coding: utf-8 -*-
2 2 # This program is free software: you can redistribute it and/or modify
3 3 # it under the terms of the GNU General Public License as published by
4 4 # the Free Software Foundation, either version 3 of the License, or
5 5 # (at your option) any later version.
6 6 #
7 7 # This program is distributed in the hope that it will be useful,
8 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 # GNU General Public License for more details.
11 11 #
12 12 # You should have received a copy of the GNU General Public License
13 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 """
15 15 kallithea.lib.paster_commands.install_iis
16 16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17 17
18 18 IIS installation tools for Kallithea
19 19 """
20 20
21 21
22 22 import os
23 23 import sys
24 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 default_verbosity = 1
30 max_args = 1
31 min_args = 1
32 summary = 'Setup IIS given a config file'
33 usage = 'CONFIG_FILE'
29 class Command(BasePasterCommand):
30 '''Kallithea: Install into IIS using isapi-wsgi'''
34 31
35 description = '''
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')
32 requires_db_session = False
45 33
46 def command(self):
47 config_spec = self.args[0]
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)
34 def take_action(self, args):
35 config_file = os.path.abspath(args.config_file)
52 36 try:
53 37 import isapi_wsgi
54 38 except ImportError:
55 raise BadCommand('missing requirement: isapi-wsgi not installed')
39 self.error('missing requirement: isapi-wsgi not installed')
56 40
57 41 file = '''\
58 42 # Created by Kallithea install_iis
59 43 import sys
60 44
61 45 if hasattr(sys, "isapidllhandle"):
62 46 import win32traceutil
63 47
64 48 import isapi_wsgi
65 49 import os
66 50
67 51 def __ExtensionFactory__():
68 52 from paste.deploy import loadapp
69 53 from paste.script.util.logging_config import fileConfig
70 54 fileConfig('%(inifile)s')
71 55 application = loadapp('config:%(inifile)s')
72 56
73 57 def app(environ, start_response):
74 58 user = environ.get('REMOTE_USER', None)
75 59 if user is not None:
76 60 os.environ['REMOTE_USER'] = user
77 61 return application(environ, start_response)
78 62
79 63 return isapi_wsgi.ISAPIThreadPoolHandler(app)
80 64
81 65 if __name__=='__main__':
82 66 from isapi.install import *
83 67 params = ISAPIParameters()
84 68 sm = [ScriptMapParams(Extension="*", Flags=0)]
85 69 vd = VirtualDirParameters(Name="%(virtualdir)s",
86 70 Description = "Kallithea",
87 71 ScriptMaps = sm,
88 72 ScriptMapUpdate = "replace")
89 73 params.VirtualDirs = [vd]
90 74 HandleCommandLine(params)
91 75 '''
92 76
93 77 outdata = file % {
94 78 'inifile': config_file.replace('\\', '\\\\'),
95 'virtualdir': self.options.virtualdir
79 'virtualdir': args.virtualdir,
96 80 }
97 81
98 82 dispatchfile = os.path.join(os.getcwd(), 'dispatch.py')
99 83 self.ensure_file(dispatchfile, outdata, False)
100 84 print 'Generating %s' % (dispatchfile,)
101 85
102 86 print ('Run \'python "%s" install\' with administrative privileges '
103 87 'to generate the _dispatch.dll file and install it into the '
104 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 1 # -*- coding: utf-8 -*-
2 2 # This program is free software: you can redistribute it and/or modify
3 3 # it under the terms of the GNU General Public License as published by
4 4 # the Free Software Foundation, either version 3 of the License, or
5 5 # (at your option) any later version.
6 6 #
7 7 # This program is distributed in the hope that it will be useful,
8 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 # GNU General Public License for more details.
11 11 #
12 12 # You should have received a copy of the GNU General Public License
13 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 """
15 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 20 This file was forked by the Kallithea project in July 2014.
21 21 Original author and date, and relevant copyright and licensing information is below:
22 22 :created_on: Apr 4, 2013
23 23 :author: marcink
24 24 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 25 :license: GPLv3, see LICENSE.md for more details.
26 26 """
27 27
28 28
29 29 import os
30 30 import sys
31 31
32 32 # imports, used in IPython shell
33 33 import time
34 34 import shutil
35 35 import datetime
36 36 from kallithea.model.db import *
37 37
38 38 from kallithea.lib.paster_commands.common import BasePasterCommand
39 39
40 40
41 41 class Command(BasePasterCommand):
42
43 max_args = 1
44 min_args = 1
42 "Kallithea: Interactive Python shell"
45 43
46 usage = "CONFIG_FILE"
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
44 def take_action(self, args):
56 45 try:
57 46 from IPython import embed
58 47 from IPython.config.loader import Config
59 48 cfg = Config()
60 49 cfg.InteractiveShellEmbed.confirm_exit = False
61 50 embed(config=cfg, banner1="Kallithea IShell.")
62 51 except ImportError:
63 52 print 'Kallithea ishell requires the IPython Python package'
64 53 sys.exit(-1)
65
66 def update_parser(self):
67 pass
@@ -1,106 +1,100 b''
1 1 # -*- coding: utf-8 -*-
2 2 # This program is free software: you can redistribute it and/or modify
3 3 # it under the terms of the GNU General Public License as published by
4 4 # the Free Software Foundation, either version 3 of the License, or
5 5 # (at your option) any later version.
6 6 #
7 7 # This program is distributed in the hope that it will be useful,
8 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 # GNU General Public License for more details.
11 11 #
12 12 # You should have received a copy of the GNU General Public License
13 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 """
15 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 20 This file was forked by the Kallithea project in July 2014.
21 21 Original author and date, and relevant copyright and licensing information is below:
22 22 :created_on: Aug 17, 2010
23 23 :author: marcink
24 24 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 25 :license: GPLv3, see LICENSE.md for more details.
26 26 """
27 27
28 28
29 29 import os
30 30 import sys
31 31 from os.path import dirname
32 32
33 33 from string import strip
34 34 from kallithea.model.repo import RepoModel
35 35 from kallithea.lib.paster_commands.common import BasePasterCommand
36 36 from kallithea.lib.utils import load_rcextensions
37 37
38 38
39 39 class Command(BasePasterCommand):
40
41 max_args = 1
42 min_args = 1
40 "Kallithea: Create or update full text search index"
43 41
44 usage = "CONFIG_FILE"
45 group_name = "Kallithea"
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
42 def take_action(self, args):
43 from pylons import config
54 44 index_location = config['index_dir']
55 45 load_rcextensions(config['here'])
56 46
57 repo_location = self.options.repo_location \
58 if self.options.repo_location else RepoModel().repos_path
59 repo_list = map(strip, self.options.repo_list.split(',')) \
60 if self.options.repo_list else None
47 repo_location = args.repo_location \
48 if args.repo_location else RepoModel().repos_path
49 repo_list = map(strip, args.repo_list.split(',')) \
50 if args.repo_list else None
61 51
62 repo_update_list = map(strip, self.options.repo_update_list.split(',')) \
63 if self.options.repo_update_list else None
52 repo_update_list = map(strip, args.repo_update_list.split(',')) \
53 if args.repo_update_list else None
64 54
65 55 #======================================================================
66 56 # WHOOSH DAEMON
67 57 #======================================================================
68 58 from kallithea.lib.pidlock import LockHeld, DaemonLock
69 59 from kallithea.lib.indexers.daemon import WhooshIndexingDaemon
70 60 try:
71 61 l = DaemonLock(file_=os.path.join(dirname(dirname(index_location)),
72 62 'make_index.lock'))
73 63 WhooshIndexingDaemon(index_location=index_location,
74 64 repo_location=repo_location,
75 65 repo_list=repo_list,
76 66 repo_update_list=repo_update_list) \
77 .run(full_index=self.options.full_index)
67 .run(full_index=args.full_index)
78 68 l.release()
79 69 except LockHeld:
80 70 sys.exit(1)
81 71
82 def update_parser(self):
83 self.parser.add_option('--repo-location',
72 def get_parser(self, prog_name):
73 parser = super(Command, self).get_parser(prog_name)
74
75 parser.add_argument('--repo-location',
84 76 action='store',
85 77 dest='repo_location',
86 78 help="Specifies repositories location to index OPTIONAL",
87 79 )
88 self.parser.add_option('--index-only',
80 parser.add_argument('--index-only',
89 81 action='store',
90 82 dest='repo_list',
91 83 help="Specifies a comma separated list of repositories "
92 84 "to build index on. If not given all repositories "
93 85 "are scanned for indexing. OPTIONAL",
94 86 )
95 self.parser.add_option('--update-only',
87 parser.add_argument('--update-only',
96 88 action='store',
97 89 dest='repo_update_list',
98 90 help="Specifies a comma separated list of repositories "
99 91 "to re-build index on. OPTIONAL",
100 92 )
101 self.parser.add_option('-f',
93 parser.add_argument('-f',
102 94 action='store_true',
103 95 dest='full_index',
104 96 help="Specifies that index should be made full i.e"
105 97 " destroy old and build from scratch",
106 98 default=False)
99
100 return parser
@@ -1,75 +1,66 b''
1 1 # -*- coding: utf-8 -*-
2 2 # This program is free software: you can redistribute it and/or modify
3 3 # it under the terms of the GNU General Public License as published by
4 4 # the Free Software Foundation, either version 3 of the License, or
5 5 # (at your option) any later version.
6 6 #
7 7 # This program is distributed in the hope that it will be useful,
8 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 # GNU General Public License for more details.
11 11 #
12 12 # You should have received a copy of the GNU General Public License
13 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 """
15 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 20 This file was forked by the Kallithea project in July 2014.
21 21 Original author and date, and relevant copyright and licensing information is below:
22 22 :created_on: Mar 6, 2012
23 23 :author: marcink
24 24 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 25 :license: GPLv3, see LICENSE.md for more details.
26 26 """
27 27
28 28
29 29 import os
30 30 import sys
31 31 import pkg_resources
32 32
33 33 from kallithea.lib.paster_commands.common import ask_ok, BasePasterCommand
34 34
35 35
36 36 class Command(BasePasterCommand):
37
38 max_args = 1
39 min_args = 1
37 """Kallithea: Write template file for extending Kallithea in Python
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
48 the ini file. Local customizations in that file will survive upgrades.
49 The file contains instructions on how it can be customized.
50 '''
39 A rcextensions directory with a __init__.py file will be created next to
40 the ini file. Local customizations in that file will survive upgrades.
41 The file contains instructions on how it can be customized.
42 """
51 43
52 def command(self):
53 from tg import config
44 takes_config_file = False
45
46 def take_action(self, args):
47 from pylons import config
54 48
55 49 here = config['here']
56 50 content = pkg_resources.resource_string(
57 51 'kallithea', os.path.join('config', 'rcextensions', '__init__.py')
58 52 )
59 53 ext_file = os.path.join(here, 'rcextensions', '__init__.py')
60 54 if os.path.exists(ext_file):
61 55 msg = ('Extension file already exists, do you want '
62 56 'to overwrite it ? [y/n]')
63 57 if not ask_ok(msg):
64 58 print 'Nothing done, exiting...'
65 59 return
66 60
67 61 dirname = os.path.dirname(ext_file)
68 62 if not os.path.isdir(dirname):
69 63 os.makedirs(dirname)
70 64 with open(ext_file, 'wb') as f:
71 65 f.write(content)
72 66 print 'Wrote new extensions file to %s' % ext_file
73
74 def update_parser(self):
75 pass
@@ -1,70 +1,68 b''
1 1 # -*- coding: utf-8 -*-
2 2 # This program is free software: you can redistribute it and/or modify
3 3 # it under the terms of the GNU General Public License as published by
4 4 # the Free Software Foundation, either version 3 of the License, or
5 5 # (at your option) any later version.
6 6 #
7 7 # This program is distributed in the hope that it will be useful,
8 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 # GNU General Public License for more details.
11 11 #
12 12 # You should have received a copy of the GNU General Public License
13 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 """
15 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 20 This file was forked by the Kallithea project in July 2014.
21 21 Original author and date, and relevant copyright and licensing information is below:
22 22 :created_on: Feb 9, 2013
23 23 :author: marcink
24 24 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 25 :license: GPLv3, see LICENSE.md for more details.
26 26 """
27 27
28 28
29 29 import os
30 30 import sys
31 31
32 32 from kallithea.model.scm import ScmModel
33 33 from kallithea.lib.paster_commands.common import BasePasterCommand
34 34 from kallithea.lib.utils import repo2db_mapper
35 35
36 36
37 37 class Command(BasePasterCommand):
38
39 max_args = 1
40 min_args = 1
38 """Kallithea: Scan file system for repositories
41 39
42 usage = "CONFIG_FILE"
43 group_name = "Kallithea"
44 takes_config_file = -1
45 parser = BasePasterCommand.standard_parser(verbose=True)
46 summary = "Rescan default location for new repositories"
40 Search under the repository root configured in the database,
41 all new repositories, and report missing ones with an option of removing them.
42 """
47 43
48 def command(self):
49 #get SqlAlchemy session
50 self._init_session()
51 rm_obsolete = self.options.delete_obsolete
44 def take_action(self, args):
45 rm_obsolete = args.delete_obsolete
52 46 print 'Now scanning root location for new repos ...'
53 47 added, removed = repo2db_mapper(ScmModel().repo_scan(),
54 48 remove_obsolete=rm_obsolete)
55 49 added = ', '.join(added) or '-'
56 50 removed = ', '.join(removed) or '-'
57 51 print 'Scan completed.'
58 52 print 'Added: %s' % added
59 53 if rm_obsolete:
60 54 print 'Removed: %s' % removed
61 55 else:
62 56 print 'Missing: %s' % removed
63 57
64 def update_parser(self):
65 self.parser.add_option(
58 def get_parser(self, prog_name):
59 parser = super(Command, self).get_parser(prog_name)
60
61 parser.add_argument(
66 62 '--delete-obsolete',
67 63 action='store_true',
68 64 help="Use this flag do delete repositories that are "
69 65 "present in Kallithea database but not on the filesystem",
70 66 )
67
68 return parser
@@ -1,126 +1,107 b''
1 1 # -*- coding: utf-8 -*-
2 2 # This program is free software: you can redistribute it and/or modify
3 3 # it under the terms of the GNU General Public License as published by
4 4 # the Free Software Foundation, either version 3 of the License, or
5 5 # (at your option) any later version.
6 6 #
7 7 # This program is distributed in the hope that it will be useful,
8 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 # GNU General Public License for more details.
11 11 #
12 12 # You should have received a copy of the GNU General Public License
13 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 """
15 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 22 import os
23 23 import sys
24 from paste.script.appinstall import AbstractInstallCommand
25 from paste.script.command import BadCommand
26 from paste.deploy import appconfig
24 import paste.deploy
25
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
40 the second part of a two-phase web application installation
41 process (the first phase is prepare-app). The setup process
42 consist of things like setting up databases, creating super user
36 Setup Kallithea according to its configuration file. This is
37 the second part of a two-phase web application installation
38 process (the first phase is prepare-app). The setup process
39 consist of things like setting up databases and creating the admin user
43 40 """
44 41
45 parser = AbstractInstallCommand.standard_parser(
46 simulate=True, quiet=True, interactive=True)
47 parser.add_option('--user',
48 action='store',
49 dest='username',
50 default=None,
51 help='Admin Username')
52 parser.add_option('--email',
53 action='store',
54 dest='email',
55 default=None,
56 help='Admin Email')
57 parser.add_option('--password',
58 action='store',
59 dest='password',
60 default=None,
61 help='Admin password min 6 chars')
62 parser.add_option('--repos',
63 action='store',
64 dest='repos_location',
65 default=None,
66 help='Absolute path to repositories location')
67 parser.add_option('--name',
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',
74 dest='force_ask',
75 default=None,
76 help='Force yes to every question')
77 parser.add_option('--force-no',
78 action='store_false',
79 dest='force_ask',
80 default=None,
81 help='Force no to every question')
82 parser.add_option('--public-access',
83 action='store_true',
84 dest='public_access',
85 default=None,
86 help='Enable public access on this installation (default)')
87 parser.add_option('--no-public-access',
88 action='store_false',
89 dest='public_access',
90 default=None,
91 help='Disable public access on this installation ')
42 def get_description(self):
43 return self.__doc__.splitlines()[0]
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)
92 49
93 def command(self):
94 config_spec = self.args[0]
95 section = self.options.section_name
96 if section is None:
97 if '#' in config_spec:
98 config_spec, section = config_spec.split('#', 1)
99 else:
100 section = 'main'
101 if not ':' in section:
102 plain_section = section
103 section = 'app:' + section
104 else:
105 plain_section = section.split(':', 1)[0]
106 if not config_spec.startswith('config:'):
107 config_spec = 'config:' + config_spec
108 if plain_section != 'main':
109 config_spec += '#' + plain_section
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)
50 parser.add_argument('--user',
51 action='store',
52 dest='username',
53 default=None,
54 help='Admin Username')
55 parser.add_argument('--email',
56 action='store',
57 dest='email',
58 default=None,
59 help='Admin Email')
60 parser.add_argument('--password',
61 action='store',
62 dest='password',
63 default=None,
64 help='Admin password min 6 chars')
65 parser.add_argument('--repos',
66 action='store',
67 dest='repos_location',
68 default=None,
69 help='Absolute path to repositories location')
70 parser.add_argument('--force-yes',
71 action='store_true',
72 dest='force_ask',
73 default=None,
74 help='Force yes to every question')
75 parser.add_argument('--force-no',
76 action='store_false',
77 dest='force_ask',
78 default=None,
79 help='Force no to every question')
80 parser.add_argument('--public-access',
81 action='store_true',
82 dest='public_access',
83 default=None,
84 help='Enable public access on this installation (default)')
85 parser.add_argument('--no-public-access',
86 action='store_false',
87 dest='public_access',
88 default=None,
89 help='Disable public access on this installation ')
90
91 return parser
92
93 def take_action(self, opts):
94 path_to_ini_file = os.path.realpath(opts.config_file)
95 conf = paste.deploy.appconfig('config:' + path_to_ini_file)
96
97 dbconf = conf['sqlalchemy.url']
98 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=conf['here'],
99 tests=False, cli_args=vars(opts))
100 dbmanage.create_tables(override=True)
101 opts = dbmanage.config_prompt(None)
102 dbmanage.create_settings(opts)
103 dbmanage.create_default_user()
104 dbmanage.admin_prompt()
105 dbmanage.create_permissions()
106 dbmanage.populate_default_permissions()
107 Session().commit()
@@ -1,84 +1,76 b''
1 1 # -*- coding: utf-8 -*-
2 2 # This program is free software: you can redistribute it and/or modify
3 3 # it under the terms of the GNU General Public License as published by
4 4 # the Free Software Foundation, either version 3 of the License, or
5 5 # (at your option) any later version.
6 6 #
7 7 # This program is distributed in the hope that it will be useful,
8 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 # GNU General Public License for more details.
11 11 #
12 12 # You should have received a copy of the GNU General Public License
13 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 """
15 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 20 This file was forked by the Kallithea project in July 2014.
21 21 Original author and date, and relevant copyright and licensing information is below:
22 22 :created_on: Jul 14, 2012
23 23 :author: marcink
24 24 :copyright: (c) 2013 RhodeCode GmbH, and others.
25 25 :license: GPLv3, see LICENSE.md for more details.
26 26 """
27 27
28 28
29 29 import os
30 30 import sys
31 31 import string
32 32
33 33 from kallithea.lib.paster_commands.common import BasePasterCommand
34 34 from kallithea.lib.utils2 import safe_unicode
35 35 from kallithea.model.db import Repository
36 36 from kallithea.model.repo import RepoModel
37 37 from kallithea.model.meta import Session
38 38
39 39
40 40 class Command(BasePasterCommand):
41
42 max_args = 1
43 min_args = 1
41 "Kallithea: Update database cache of repository data"
44 42
45 usage = "CONFIG_FILE"
46 group_name = "Kallithea"
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:
43 def take_action(self, args):
44 if args.repo_update_list is None:
57 45 repo_list = Repository.query().all()
58 46 else:
59 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 49 repo_list = list(Repository.query()
62 50 .filter(Repository.repo_name.in_(repo_names)))
63 51 for repo in repo_list:
64 52 repo.update_changeset_cache()
65 53 Session().commit()
66 54
67 if self.options.invalidate_cache:
55 if args.invalidate_cache:
68 56 for r in repo_list:
69 57 r.set_invalidate()
70 58 print 'Updated repo info and invalidated cache for %s repositories' % (len(repo_list))
71 59 else:
72 60 print 'Updated repo info for %s repositories' % (len(repo_list))
73 61
74 def update_parser(self):
75 self.parser.add_option('--update-only',
62 def get_parser(self, prog_name):
63 parser = super(Command, self).get_parser(prog_name)
64
65 parser.add_argument('--update-only',
76 66 action='store',
77 67 dest='repo_update_list',
78 68 help="Specifies a comma separated list of repositories "
79 69 "to update last commit info for. OPTIONAL")
80 self.parser.add_option('--invalidate-cache',
70 parser.add_argument('--invalidate-cache',
81 71 action='store_true',
82 72 dest='invalidate_cache',
83 73 help="Trigger cache invalidation event for repos. "
84 74 "OPTIONAL")
75
76 return parser
@@ -1,562 +1,562 b''
1 1 # -*- coding: utf-8 -*-
2 2 # This program is free software: you can redistribute it and/or modify
3 3 # it under the terms of the GNU General Public License as published by
4 4 # the Free Software Foundation, either version 3 of the License, or
5 5 # (at your option) any later version.
6 6 #
7 7 # This program is distributed in the hope that it will be useful,
8 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 # GNU General Public License for more details.
11 11 #
12 12 # You should have received a copy of the GNU General Public License
13 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 """
15 15 kallithea.tests.other.manual_test_vcs_operations
16 16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17 17
18 18 Test suite for making push/pull operations.
19 19
20 20 Run it in two terminals::
21 paster serve kallithea/tests/test.ini
21 gearbox serve -c kallithea/tests/test.ini
22 22 KALLITHEA_WHOOSH_TEST_DISABLE=1 KALLITHEA_NO_TMP_PATH=1 py.test kallithea/tests/other/manual_test_vcs_operations.py
23 23
24 24 You must have git > 1.8.1 for tests to work fine
25 25
26 26 This file was forked by the Kallithea project in July 2014.
27 27 Original author and date, and relevant copyright and licensing information is below:
28 28 :created_on: Dec 30, 2010
29 29 :author: marcink
30 30 :copyright: (c) 2013 RhodeCode GmbH, and others.
31 31 :license: GPLv3, see LICENSE.md for more details.
32 32
33 33 """
34 34
35 35 import os
36 36 import re
37 37 import tempfile
38 38 import time
39 39
40 40 from tempfile import _RandomNameSequence
41 41 from subprocess import Popen, PIPE
42 42
43 43 from kallithea.tests.base import *
44 44 from kallithea.tests.fixture import Fixture
45 45 from kallithea.model.db import User, Repository, UserIpMap, CacheInvalidation
46 46 from kallithea.model.meta import Session
47 47 from kallithea.model.repo import RepoModel
48 48 from kallithea.model.user import UserModel
49 49
50 50 DEBUG = True
51 51 HOST = '127.0.0.1:4999' # test host
52 52
53 53 fixture = Fixture()
54 54
55 55
56 56 class Command(object):
57 57
58 58 def __init__(self, cwd):
59 59 self.cwd = cwd
60 60
61 61 def execute(self, cmd, *args, **environ):
62 62 """
63 63 Runs command on the system with given ``args``.
64 64 """
65 65
66 66 command = cmd + ' ' + ' '.join(args)
67 67 if DEBUG:
68 68 print '*** CMD %s ***' % command
69 69 testenv = dict(os.environ)
70 70 testenv['LANG'] = 'en_US.UTF-8'
71 71 testenv['LANGUAGE'] = 'en_US:en'
72 72 testenv.update(environ)
73 73 p = Popen(command, shell=True, stdout=PIPE, stderr=PIPE, cwd=self.cwd, env=testenv)
74 74 stdout, stderr = p.communicate()
75 75 if DEBUG:
76 76 if stdout:
77 77 print 'stdout:', repr(stdout)
78 78 if stderr:
79 79 print 'stderr:', repr(stderr)
80 80 return stdout, stderr
81 81
82 82
83 83 def _get_tmp_dir():
84 84 return tempfile.mkdtemp(prefix='rc_integration_test')
85 85
86 86
87 87 def _construct_url(repo, dest=None, **kwargs):
88 88 if dest is None:
89 89 #make temp clone
90 90 dest = _get_tmp_dir()
91 91 params = {
92 92 'user': TEST_USER_ADMIN_LOGIN,
93 93 'passwd': TEST_USER_ADMIN_PASS,
94 94 'host': HOST,
95 95 'cloned_repo': repo,
96 96 'dest': dest
97 97 }
98 98 params.update(**kwargs)
99 99 if params['user'] and params['passwd']:
100 100 _url = 'http://%(user)s:%(passwd)s@%(host)s/%(cloned_repo)s %(dest)s' % params
101 101 else:
102 102 _url = 'http://(host)s/%(cloned_repo)s %(dest)s' % params
103 103 return _url
104 104
105 105
106 106 def _add_files_and_push(vcs, DEST, **kwargs):
107 107 """
108 108 Generate some files, add it to DEST repo and push back
109 109 vcs is git or hg and defines what VCS we want to make those files for
110 110
111 111 :param vcs:
112 112 :param DEST:
113 113 """
114 114 # commit some stuff into this repo
115 115 cwd = path = os.path.join(DEST)
116 116 #added_file = os.path.join(path, '%ssetupΔ…ΕΌΕΊΔ‡.py' % _RandomNameSequence().next())
117 117 added_file = os.path.join(path, '%ssetup.py' % _RandomNameSequence().next())
118 118 Command(cwd).execute('touch %s' % added_file)
119 119 Command(cwd).execute('%s add %s' % (vcs, added_file))
120 120
121 121 email = 'me@example.com'
122 122 if os.name == 'nt':
123 123 author_str = 'User <%s>' % email
124 124 else:
125 125 author_str = 'User ǝɯɐᴎ <%s>' % email
126 126 for i in xrange(kwargs.get('files_no', 3)):
127 127 cmd = """echo "added_line%s" >> %s""" % (i, added_file)
128 128 Command(cwd).execute(cmd)
129 129 if vcs == 'hg':
130 130 cmd = """hg commit -m "committed new %s" -u "%s" "%s" """ % (
131 131 i, author_str, added_file
132 132 )
133 133 elif vcs == 'git':
134 134 cmd = """git commit -m "committed new %s" --author "%s" "%s" """ % (
135 135 i, author_str, added_file
136 136 )
137 137 # git commit needs EMAIL on some machines
138 138 Command(cwd).execute(cmd, EMAIL=email)
139 139
140 140 # PUSH it back
141 141 _REPO = None
142 142 if vcs == 'hg':
143 143 _REPO = HG_REPO
144 144 elif vcs == 'git':
145 145 _REPO = GIT_REPO
146 146
147 147 kwargs['dest'] = ''
148 148 clone_url = _construct_url(_REPO, **kwargs)
149 149 if 'clone_url' in kwargs:
150 150 clone_url = kwargs['clone_url']
151 151 stdout = stderr = None
152 152 if vcs == 'hg':
153 153 stdout, stderr = Command(cwd).execute('hg push --verbose', clone_url)
154 154 elif vcs == 'git':
155 155 stdout, stderr = Command(cwd).execute('git push --verbose', clone_url + " master")
156 156
157 157 return stdout, stderr
158 158
159 159
160 160 def set_anonymous_access(enable=True):
161 161 user = User.get_default_user()
162 162 user.active = enable
163 163 Session().commit()
164 164 print '\tanonymous access is now:', enable
165 165 if enable != User.get_default_user().active:
166 166 raise Exception('Cannot set anonymous access')
167 167
168 168
169 169 #==============================================================================
170 170 # TESTS
171 171 #==============================================================================
172 172
173 173
174 174 def _check_proper_git_push(stdout, stderr):
175 175 #WTF Git stderr is output ?!
176 176 assert 'fatal' not in stderr
177 177 assert 'rejected' not in stderr
178 178 assert 'Pushing to' in stderr
179 179 assert 'master -> master' in stderr
180 180
181 181
182 182 class TestVCSOperations(TestController):
183 183
184 184 @classmethod
185 185 def setup_class(cls):
186 186 #DISABLE ANONYMOUS ACCESS
187 187 set_anonymous_access(False)
188 188
189 189 def setup_method(self, method):
190 190 r = Repository.get_by_repo_name(GIT_REPO)
191 191 Repository.unlock(r)
192 192 r.enable_locking = False
193 193 Session().commit()
194 194
195 195 r = Repository.get_by_repo_name(HG_REPO)
196 196 Repository.unlock(r)
197 197 r.enable_locking = False
198 198 Session().commit()
199 199
200 200 def test_clone_hg_repo_by_admin(self):
201 201 clone_url = _construct_url(HG_REPO)
202 202 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
203 203
204 204 assert 'requesting all changes' in stdout
205 205 assert 'adding changesets' in stdout
206 206 assert 'adding manifests' in stdout
207 207 assert 'adding file changes' in stdout
208 208
209 209 assert stderr == ''
210 210
211 211 def test_clone_git_repo_by_admin(self):
212 212 clone_url = _construct_url(GIT_REPO)
213 213 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
214 214
215 215 assert 'Cloning into' in stdout + stderr
216 216 assert stderr == '' or stdout == ''
217 217
218 218 def test_clone_wrong_credentials_hg(self):
219 219 clone_url = _construct_url(HG_REPO, passwd='bad!')
220 220 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
221 221 assert 'abort: authorization failed' in stderr
222 222
223 223 def test_clone_wrong_credentials_git(self):
224 224 clone_url = _construct_url(GIT_REPO, passwd='bad!')
225 225 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
226 226 assert 'fatal: Authentication failed' in stderr
227 227
228 228 def test_clone_git_dir_as_hg(self):
229 229 clone_url = _construct_url(GIT_REPO)
230 230 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
231 231 assert 'HTTP Error 404: Not Found' in stderr
232 232
233 233 def test_clone_hg_repo_as_git(self):
234 234 clone_url = _construct_url(HG_REPO)
235 235 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
236 236 assert 'not found' in stderr
237 237
238 238 def test_clone_non_existing_path_hg(self):
239 239 clone_url = _construct_url('trololo')
240 240 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
241 241 assert 'HTTP Error 404: Not Found' in stderr
242 242
243 243 def test_clone_non_existing_path_git(self):
244 244 clone_url = _construct_url('trololo')
245 245 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
246 246 assert 'not found' in stderr
247 247
248 248 def test_push_new_file_hg(self):
249 249 DEST = _get_tmp_dir()
250 250 clone_url = _construct_url(HG_REPO, dest=DEST)
251 251 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
252 252
253 253 fork_name = '%s_fork%s' % (HG_REPO, _RandomNameSequence().next())
254 254 fixture.create_fork(HG_REPO, fork_name)
255 255 clone_url = _construct_url(fork_name).split()[0]
256 256 stdout, stderr = _add_files_and_push('hg', DEST, clone_url=clone_url)
257 257
258 258 assert 'pushing to' in stdout
259 259 assert 'Repository size' in stdout
260 260 assert 'Last revision is now' in stdout
261 261
262 262 def test_push_new_file_git(self):
263 263 DEST = _get_tmp_dir()
264 264 clone_url = _construct_url(GIT_REPO, dest=DEST)
265 265 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
266 266
267 267 # commit some stuff into this repo
268 268 fork_name = '%s_fork%s' % (GIT_REPO, _RandomNameSequence().next())
269 269 fixture.create_fork(GIT_REPO, fork_name)
270 270 clone_url = _construct_url(fork_name).split()[0]
271 271 stdout, stderr = _add_files_and_push('git', DEST, clone_url=clone_url)
272 272 print [(x.repo_full_path,x.repo_path) for x in Repository.query()] # TODO: what is this for
273 273 _check_proper_git_push(stdout, stderr)
274 274
275 275 def test_push_invalidates_cache_hg(self):
276 276 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
277 277 ==HG_REPO).scalar()
278 278 if not key:
279 279 key = CacheInvalidation(HG_REPO, HG_REPO)
280 280 Session().add(key)
281 281
282 282 key.cache_active = True
283 283 Session().commit()
284 284
285 285 DEST = _get_tmp_dir()
286 286 clone_url = _construct_url(HG_REPO, dest=DEST)
287 287 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
288 288
289 289 fork_name = '%s_fork%s' % (HG_REPO, _RandomNameSequence().next())
290 290 fixture.create_fork(HG_REPO, fork_name)
291 291 clone_url = _construct_url(fork_name).split()[0]
292 292 stdout, stderr = _add_files_and_push('hg', DEST, files_no=1, clone_url=clone_url)
293 293
294 294 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
295 295 ==fork_name).all()
296 296 assert key == []
297 297
298 298 def test_push_invalidates_cache_git(self):
299 299 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
300 300 ==GIT_REPO).scalar()
301 301 if not key:
302 302 key = CacheInvalidation(GIT_REPO, GIT_REPO)
303 303 Session().add(key)
304 304
305 305 key.cache_active = True
306 306 Session().commit()
307 307
308 308 DEST = _get_tmp_dir()
309 309 clone_url = _construct_url(GIT_REPO, dest=DEST)
310 310 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
311 311
312 312 # commit some stuff into this repo
313 313 fork_name = '%s_fork%s' % (GIT_REPO, _RandomNameSequence().next())
314 314 fixture.create_fork(GIT_REPO, fork_name)
315 315 clone_url = _construct_url(fork_name).split()[0]
316 316 stdout, stderr = _add_files_and_push('git', DEST, files_no=1, clone_url=clone_url)
317 317 _check_proper_git_push(stdout, stderr)
318 318
319 319 key = CacheInvalidation.query().filter(CacheInvalidation.cache_key
320 320 ==fork_name).all()
321 321 assert key == []
322 322
323 323 def test_push_wrong_credentials_hg(self):
324 324 DEST = _get_tmp_dir()
325 325 clone_url = _construct_url(HG_REPO, dest=DEST)
326 326 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
327 327
328 328 stdout, stderr = _add_files_and_push('hg', DEST, user='bad',
329 329 passwd='name')
330 330
331 331 assert 'abort: authorization failed' in stderr
332 332
333 333 def test_push_wrong_credentials_git(self):
334 334 DEST = _get_tmp_dir()
335 335 clone_url = _construct_url(GIT_REPO, dest=DEST)
336 336 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
337 337
338 338 stdout, stderr = _add_files_and_push('git', DEST, user='bad',
339 339 passwd='name')
340 340
341 341 assert 'fatal: Authentication failed' in stderr
342 342
343 343 def test_push_back_to_wrong_url_hg(self):
344 344 DEST = _get_tmp_dir()
345 345 clone_url = _construct_url(HG_REPO, dest=DEST)
346 346 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
347 347
348 348 stdout, stderr = _add_files_and_push('hg', DEST,
349 349 clone_url='http://%s/tmp' % HOST)
350 350
351 351 assert 'HTTP Error 404: Not Found' in stderr
352 352
353 353 def test_push_back_to_wrong_url_git(self):
354 354 DEST = _get_tmp_dir()
355 355 clone_url = _construct_url(GIT_REPO, dest=DEST)
356 356 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
357 357
358 358 stdout, stderr = _add_files_and_push('git', DEST,
359 359 clone_url='http://%s/tmp' % HOST)
360 360
361 361 assert 'not found' in stderr
362 362
363 363 def test_clone_and_create_lock_hg(self):
364 364 # enable locking
365 365 r = Repository.get_by_repo_name(HG_REPO)
366 366 r.enable_locking = True
367 367 Session().commit()
368 368 # clone
369 369 clone_url = _construct_url(HG_REPO)
370 370 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
371 371
372 372 #check if lock was made
373 373 r = Repository.get_by_repo_name(HG_REPO)
374 374 assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
375 375
376 376 def test_clone_and_create_lock_git(self):
377 377 # enable locking
378 378 r = Repository.get_by_repo_name(GIT_REPO)
379 379 r.enable_locking = True
380 380 Session().commit()
381 381 # clone
382 382 clone_url = _construct_url(GIT_REPO)
383 383 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
384 384
385 385 #check if lock was made
386 386 r = Repository.get_by_repo_name(GIT_REPO)
387 387 assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
388 388
389 389 def test_clone_after_repo_was_locked_hg(self):
390 390 #lock repo
391 391 r = Repository.get_by_repo_name(HG_REPO)
392 392 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
393 393 #pull fails since repo is locked
394 394 clone_url = _construct_url(HG_REPO)
395 395 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
396 396 msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
397 397 % (HG_REPO, TEST_USER_ADMIN_LOGIN))
398 398 assert msg in stderr
399 399
400 400 def test_clone_after_repo_was_locked_git(self):
401 401 #lock repo
402 402 r = Repository.get_by_repo_name(GIT_REPO)
403 403 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
404 404 #pull fails since repo is locked
405 405 clone_url = _construct_url(GIT_REPO)
406 406 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
407 407 msg = ("""The requested URL returned error: 423""")
408 408 assert msg in stderr
409 409
410 410 def test_push_on_locked_repo_by_other_user_hg(self):
411 411 #clone some temp
412 412 DEST = _get_tmp_dir()
413 413 clone_url = _construct_url(HG_REPO, dest=DEST)
414 414 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
415 415
416 416 #lock repo
417 417 r = Repository.get_by_repo_name(HG_REPO)
418 418 # let this user actually push !
419 419 RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
420 420 perm='repository.write')
421 421 Session().commit()
422 422 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
423 423
424 424 #push fails repo is locked by other user !
425 425 stdout, stderr = _add_files_and_push('hg', DEST,
426 426 user=TEST_USER_REGULAR_LOGIN,
427 427 passwd=TEST_USER_REGULAR_PASS)
428 428 msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
429 429 % (HG_REPO, TEST_USER_ADMIN_LOGIN))
430 430 assert msg in stderr
431 431
432 432 def test_push_on_locked_repo_by_other_user_git(self):
433 433 #clone some temp
434 434 DEST = _get_tmp_dir()
435 435 clone_url = _construct_url(GIT_REPO, dest=DEST)
436 436 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
437 437
438 438 #lock repo
439 439 r = Repository.get_by_repo_name(GIT_REPO)
440 440 # let this user actually push !
441 441 RepoModel().grant_user_permission(repo=r, user=TEST_USER_REGULAR_LOGIN,
442 442 perm='repository.write')
443 443 Session().commit()
444 444 Repository.lock(r, User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id)
445 445
446 446 #push fails repo is locked by other user !
447 447 stdout, stderr = _add_files_and_push('git', DEST,
448 448 user=TEST_USER_REGULAR_LOGIN,
449 449 passwd=TEST_USER_REGULAR_PASS)
450 450 err = 'Repository `%s` locked by user `%s`' % (GIT_REPO, TEST_USER_ADMIN_LOGIN)
451 451 assert err in stderr
452 452
453 453 #TODO: fix this somehow later on Git, Git is stupid and even if we throw
454 454 #back 423 to it, it makes ANOTHER request and we fail there with 405 :/
455 455
456 456 msg = ("""abort: HTTP Error 423: Repository `%s` locked by user `%s`"""
457 457 % (GIT_REPO, TEST_USER_ADMIN_LOGIN))
458 458 #msg = "405 Method Not Allowed"
459 459 #assert msg in stderr
460 460
461 461 def test_push_unlocks_repository_hg(self):
462 462 # enable locking
463 463 fork_name = '%s_fork%s' % (HG_REPO, _RandomNameSequence().next())
464 464 fixture.create_fork(HG_REPO, fork_name)
465 465 r = Repository.get_by_repo_name(fork_name)
466 466 r.enable_locking = True
467 467 Session().commit()
468 468 #clone some temp
469 469 DEST = _get_tmp_dir()
470 470 clone_url = _construct_url(fork_name, dest=DEST)
471 471 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
472 472
473 473 #check for lock repo after clone
474 474 r = Repository.get_by_repo_name(fork_name)
475 475 uid = User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
476 476 assert r.locked[0] == uid
477 477
478 478 #push is ok and repo is now unlocked
479 479 stdout, stderr = _add_files_and_push('hg', DEST, clone_url=clone_url.split()[0])
480 480 assert str('remote: Released lock on repo `%s`' % fork_name) in stdout
481 481 #we need to cleanup the Session Here !
482 482 Session.remove()
483 483 r = Repository.get_by_repo_name(fork_name)
484 484 assert r.locked == [None, None]
485 485
486 486 #TODO: fix me ! somehow during tests hooks don't get called on Git
487 487 def test_push_unlocks_repository_git(self):
488 488 # enable locking
489 489 fork_name = '%s_fork%s' % (GIT_REPO, _RandomNameSequence().next())
490 490 fixture.create_fork(GIT_REPO, fork_name)
491 491 r = Repository.get_by_repo_name(fork_name)
492 492 r.enable_locking = True
493 493 Session().commit()
494 494 #clone some temp
495 495 DEST = _get_tmp_dir()
496 496 clone_url = _construct_url(fork_name, dest=DEST)
497 497 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
498 498
499 499 #check for lock repo after clone
500 500 r = Repository.get_by_repo_name(fork_name)
501 501 assert r.locked[0] == User.get_by_username(TEST_USER_ADMIN_LOGIN).user_id
502 502
503 503 #push is ok and repo is now unlocked
504 504 stdout, stderr = _add_files_and_push('git', DEST, clone_url=clone_url.split()[0])
505 505 _check_proper_git_push(stdout, stderr)
506 506
507 507 assert ('remote: Released lock on repo `%s`' % fork_name) in stderr
508 508 #we need to cleanup the Session Here !
509 509 Session.remove()
510 510 r = Repository.get_by_repo_name(fork_name)
511 511 assert r.locked == [None, None]
512 512
513 513 def test_ip_restriction_hg(self):
514 514 user_model = UserModel()
515 515 try:
516 516 user_model.add_extra_ip(TEST_USER_ADMIN_LOGIN, '10.10.10.10/32')
517 517 Session().commit()
518 518 clone_url = _construct_url(HG_REPO)
519 519 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
520 520 assert 'abort: HTTP Error 403: Forbidden' in stderr
521 521 finally:
522 522 #release IP restrictions
523 523 for ip in UserIpMap.query():
524 524 UserIpMap.delete(ip.ip_id)
525 525 Session().commit()
526 526
527 527 # IP permissions are cached, need to invalidate this cache explicitly
528 528 invalidate_all_caches()
529 529
530 530 clone_url = _construct_url(HG_REPO)
531 531 stdout, stderr = Command(tempfile.gettempdir()).execute('hg clone', clone_url)
532 532
533 533 assert 'requesting all changes' in stdout
534 534 assert 'adding changesets' in stdout
535 535 assert 'adding manifests' in stdout
536 536 assert 'adding file changes' in stdout
537 537
538 538 assert stderr == ''
539 539
540 540 def test_ip_restriction_git(self):
541 541 user_model = UserModel()
542 542 try:
543 543 user_model.add_extra_ip(TEST_USER_ADMIN_LOGIN, '10.10.10.10/32')
544 544 Session().commit()
545 545 clone_url = _construct_url(GIT_REPO)
546 546 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
547 547 # The message apparently changed in Git 1.8.3, so match it loosely.
548 548 assert re.search(r'\b403\b', stderr)
549 549 finally:
550 550 #release IP restrictions
551 551 for ip in UserIpMap.query():
552 552 UserIpMap.delete(ip.ip_id)
553 553 Session().commit()
554 554
555 555 # IP permissions are cached, need to invalidate this cache explicitly
556 556 invalidate_all_caches()
557 557
558 558 clone_url = _construct_url(GIT_REPO)
559 559 stdout, stderr = Command(tempfile.gettempdir()).execute('git clone', clone_url)
560 560
561 561 assert 'Cloning into' in stdout + stderr
562 562 assert stderr == '' or stdout == ''
@@ -1,17 +1,17 b''
1 1 #!/bin/sh
2 2 psql -U postgres -h localhost -c 'drop database if exists kallithea;'
3 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 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 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 8 sleep 3
9 9 kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo1 password:qweqwe email:demo1@example.com
10 10 kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo2 password:qweqwe email:demo2@example.com
11 11 kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user username:demo3 password:qweqwe email:demo3@example.com
12 12 kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 create_user_group group_name:demo12
13 13 kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 add_user_to_user_group usergroupid:demo12 userid:demo1
14 14 kallithea-api --apikey=$API_KEY --apihost=http://127.0.0.1:5001 add_user_to_user_group usergroupid:demo12 userid:demo2
15 15 echo "killing server"
16 16 kill `cat server.pid`
17 17 rm server.pid
@@ -1,605 +1,614 b''
1 1 ################################################################################
2 2 ################################################################################
3 3 # Kallithea - config for tests: #
4 4 # initial_repo_scan = true #
5 5 # sqlalchemy and kallithea_test.sqlite #
6 6 # custom logging #
7 7 # #
8 8 # The %(here)s variable will be replaced with the parent directory of this file#
9 9 ################################################################################
10 10 ################################################################################
11 11
12 12 [DEFAULT]
13 13 debug = true
14 14 pdebug = false
15 15
16 16 ################################################################################
17 17 ## Email settings ##
18 18 ## ##
19 19 ## Refer to the documentation ("Email settings") for more details. ##
20 20 ## ##
21 21 ## It is recommended to use a valid sender address that passes access ##
22 22 ## validation and spam filtering in mail servers. ##
23 23 ################################################################################
24 24
25 25 ## 'From' header for application emails. You can optionally add a name.
26 26 ## Default:
27 27 #app_email_from = Kallithea
28 28 ## Examples:
29 29 #app_email_from = Kallithea <kallithea-noreply@example.com>
30 30 #app_email_from = kallithea-noreply@example.com
31 31
32 32 ## Subject prefix for application emails.
33 33 ## A space between this prefix and the real subject is automatically added.
34 34 ## Default:
35 35 #email_prefix =
36 36 ## Example:
37 37 #email_prefix = [Kallithea]
38 38
39 39 ## Recipients for error emails and fallback recipients of application mails.
40 40 ## Multiple addresses can be specified, space-separated.
41 41 ## Only addresses are allowed, do not add any name part.
42 42 ## Default:
43 43 #email_to =
44 44 ## Examples:
45 45 #email_to = admin@example.com
46 46 #email_to = admin@example.com another_admin@example.com
47 47
48 48 ## 'From' header for error emails. You can optionally add a name.
49 49 ## Default:
50 50 #error_email_from = pylons@yourapp.com
51 51 ## Examples:
52 52 #error_email_from = Kallithea Errors <kallithea-noreply@example.com>
53 53 #error_email_from = paste_error@example.com
54 54
55 55 ## SMTP server settings
56 56 ## If specifying credentials, make sure to use secure connections.
57 57 ## Default: Send unencrypted unauthenticated mails to the specified smtp_server.
58 58 ## For "SSL", use smtp_use_ssl = true and smtp_port = 465.
59 59 ## For "STARTTLS", use smtp_use_tls = true and smtp_port = 587.
60 60 #smtp_server = smtp.example.com
61 61 #smtp_username =
62 62 #smtp_password =
63 63 #smtp_port = 25
64 64 #smtp_use_ssl = false
65 65 #smtp_use_tls = false
66 66
67 67 [server:main]
68 ## PASTE ##
69 #use = egg:Paste#http
68 ## Gearbox default web server ##
69 #use = egg:gearbox#wsgiref
70 70 ## nr of worker threads to spawn
71 71 #threadpool_workers = 1
72 72 ## max request before thread respawn
73 73 #threadpool_max_requests = 100
74 74 ## option to use threads of process
75 75 #use_threadpool = true
76 76
77 ## Gearbox gevent web server ##
78 #use = egg:gearbox#gevent
79
77 80 ## WAITRESS ##
78 81 use = egg:waitress#main
79 82 ## number of worker threads
80 83 threads = 1
81 84 ## MAX BODY SIZE 100GB
82 85 max_request_body_size = 107374182400
83 86 ## use poll instead of select, fixes fd limits, may not work on old
84 87 ## windows systems.
85 88 #asyncore_use_poll = True
86 89
87 90 ## GUNICORN ##
88 91 #use = egg:gunicorn#main
89 92 ## number of process workers. You must set `instance_id = *` when this option
90 93 ## is set to more than one worker
91 94 #workers = 1
92 95 ## process name
93 96 #proc_name = kallithea
94 97 ## type of worker class, one of sync, eventlet, gevent, tornado
95 98 ## recommended for bigger setup is using of of other than sync one
96 99 #worker_class = sync
97 100 #max_requests = 1000
98 101 ## amount of time a worker can handle request before it gets killed and
99 102 ## restarted
100 103 #timeout = 3600
101 104
102 105 ## UWSGI ##
103 106 ## run with uwsgi --ini-paste-logged <inifile.ini>
104 107 #[uwsgi]
105 108 #socket = /tmp/uwsgi.sock
106 109 #master = true
107 110 #http = 127.0.0.1:5000
108 111
109 112 ## set as deamon and redirect all output to file
110 113 #daemonize = ./uwsgi_kallithea.log
111 114
112 115 ## master process PID
113 116 #pidfile = ./uwsgi_kallithea.pid
114 117
115 118 ## stats server with workers statistics, use uwsgitop
116 119 ## for monitoring, `uwsgitop 127.0.0.1:1717`
117 120 #stats = 127.0.0.1:1717
118 121 #memory-report = true
119 122
120 123 ## log 5XX errors
121 124 #log-5xx = true
122 125
123 126 ## Set the socket listen queue size.
124 127 #listen = 256
125 128
126 129 ## Gracefully Reload workers after the specified amount of managed requests
127 130 ## (avoid memory leaks).
128 131 #max-requests = 1000
129 132
130 133 ## enable large buffers
131 134 #buffer-size = 65535
132 135
133 136 ## socket and http timeouts ##
134 137 #http-timeout = 3600
135 138 #socket-timeout = 3600
136 139
137 140 ## Log requests slower than the specified number of milliseconds.
138 141 #log-slow = 10
139 142
140 143 ## Exit if no app can be loaded.
141 144 #need-app = true
142 145
143 146 ## Set lazy mode (load apps in workers instead of master).
144 147 #lazy = true
145 148
146 149 ## scaling ##
147 150 ## set cheaper algorithm to use, if not set default will be used
148 151 #cheaper-algo = spare
149 152
150 153 ## minimum number of workers to keep at all times
151 154 #cheaper = 1
152 155
153 156 ## number of workers to spawn at startup
154 157 #cheaper-initial = 1
155 158
156 159 ## maximum number of workers that can be spawned
157 160 #workers = 4
158 161
159 162 ## how many workers should be spawned at a time
160 163 #cheaper-step = 1
161 164
162 165 ## COMMON ##
163 166 host = 127.0.0.1
164 167 #port = 5000
165 168 port = 4999
166 169
167 170 ## middleware for hosting the WSGI application under a URL prefix
168 171 #[filter:proxy-prefix]
169 172 #use = egg:PasteDeploy#prefix
170 173 #prefix = /<your-prefix>
171 174
172 175 [app:main]
173 176 use = egg:kallithea
174 177 ## enable proxy prefix middleware
175 178 #filter-with = proxy-prefix
176 179
177 180 full_stack = true
178 181 static_files = true
179 182 ## Available Languages:
180 183 ## cs de fr hu ja nl_BE pl pt_BR ru sk zh_CN zh_TW
181 184 lang =
182 185 #cache_dir = %(here)s/data
183 186 cache_dir = %(here)s/../../data/test/cache
184 187 #index_dir = %(here)s/data/index
185 188 index_dir = %(here)s/../../data/test/index
186 189
187 190 ## perform a full repository scan on each server start, this should be
188 191 ## set to false after first startup, to allow faster server restarts.
189 192 #initial_repo_scan = false
190 193 initial_repo_scan = true
191 194
192 195 ## uncomment and set this path to use archive download cache
193 196 #archive_cache_dir = %(here)s/tarballcache
194 197 archive_cache_dir = %(here)s/../../data/test/tarballcache
195 198
196 199 ## change this to unique ID for security
197 200 app_instance_uuid = test
198 201
199 202 ## cut off limit for large diffs (size in bytes)
200 203 cut_off_limit = 256000
201 204
202 205 ## force https in Kallithea, fixes https redirects, assumes it's always https
203 206 force_https = false
204 207
205 208 ## use Strict-Transport-Security headers
206 209 use_htsts = false
207 210
208 211 ## number of commits stats will parse on each iteration
209 212 commit_parse_limit = 25
210 213
211 214 ## path to git executable
212 215 git_path = git
213 216
214 217 ## git rev filter option, --all is the default filter, if you need to
215 218 ## hide all refs in changelog switch this to --branches --tags
216 219 #git_rev_filter = --branches --tags
217 220
218 221 ## RSS feed options
219 222 rss_cut_off_limit = 256000
220 223 rss_items_per_page = 10
221 224 rss_include_diff = false
222 225
223 226 ## options for showing and identifying changesets
224 227 show_sha_length = 12
225 228 #show_revision_number = false
226 229 show_revision_number = true
227 230
228 231 ## Canonical URL to use when creating full URLs in UI and texts.
229 232 ## Useful when the site is available under different names or protocols.
230 233 ## Defaults to what is provided in the WSGI environment.
231 234 #canonical_url = https://kallithea.example.com/repos
232 235
233 236 ## gist URL alias, used to create nicer urls for gist. This should be an
234 237 ## url that does rewrites to _admin/gists/<gistid>.
235 238 ## example: http://gist.example.com/{gistid}. Empty means use the internal
236 239 ## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid>
237 240 gist_alias_url =
238 241
239 242 ## white list of API enabled controllers. This allows to add list of
240 243 ## controllers to which access will be enabled by api_key. eg: to enable
241 244 ## api access to raw_files put `FilesController:raw`, to enable access to patches
242 245 ## add `ChangesetController:changeset_patch`. This list should be "," separated
243 246 ## Syntax is <ControllerClass>:<function>. Check debug logs for generated names
244 247 ## Recommended settings below are commented out:
245 248 api_access_controllers_whitelist =
246 249 # ChangesetController:changeset_patch,
247 250 # ChangesetController:changeset_raw,
248 251 # FilesController:raw,
249 252 # FilesController:archivefile
250 253
251 254 ## default encoding used to convert from and to unicode
252 255 ## can be also a comma separated list of encoding in case of mixed encodings
253 256 default_encoding = utf8
254 257
255 258 ## issue tracker for Kallithea (leave blank to disable, absent for default)
256 259 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
257 260
258 261 ## issue tracking mapping for commits messages
259 262 ## comment out issue_pat, issue_server, issue_prefix to enable
260 263
261 264 ## pattern to get the issues from commit messages
262 265 ## default one used here is #<numbers> with a regex passive group for `#`
263 266 ## {id} will be all groups matched from this pattern
264 267
265 268 issue_pat = (?:\s*#)(\d+)
266 269
267 270 ## server url to the issue, each {id} will be replaced with match
268 271 ## fetched from the regex and {repo} is replaced with full repository name
269 272 ## including groups {repo_name} is replaced with just name of repo
270 273
271 274 issue_server_link = https://issues.example.com/{repo}/issue/{id}
272 275
273 276 ## prefix to add to link to indicate it's an url
274 277 ## #314 will be replaced by <issue_prefix><id>
275 278
276 279 issue_prefix = #
277 280
278 281 ## issue_pat, issue_server_link, issue_prefix can have suffixes to specify
279 282 ## multiple patterns, to other issues server, wiki or others
280 283 ## below an example how to create a wiki pattern
281 284 # wiki-some-id -> https://wiki.example.com/some-id
282 285
283 286 #issue_pat_wiki = (?:wiki-)(.+)
284 287 #issue_server_link_wiki = https://wiki.example.com/{id}
285 288 #issue_prefix_wiki = WIKI-
286 289
287 290 ## alternative return HTTP header for failed authentication. Default HTTP
288 291 ## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
289 292 ## handling that. Set this variable to 403 to return HTTPForbidden
290 293 auth_ret_code =
291 294
292 295 ## locking return code. When repository is locked return this HTTP code. 2XX
293 296 ## codes don't break the transactions while 4XX codes do
294 297 lock_ret_code = 423
295 298
296 299 ## allows to change the repository location in settings page
297 300 allow_repo_location_change = True
298 301
299 302 ## allows to setup custom hooks in settings page
300 303 allow_custom_hooks_settings = True
301 304
302 305 ## extra extensions for indexing, space separated and without the leading '.'.
303 306 # index.extensions =
304 307 # gemfile
305 308 # lock
306 309
307 310 ## extra filenames for indexing, space separated
308 311 # index.filenames =
309 312 # .dockerignore
310 313 # .editorconfig
311 314 # INSTALL
312 315 # CHANGELOG
313 316
314 317 ####################################
315 318 ### CELERY CONFIG ####
316 319 ####################################
317 320
318 321 use_celery = false
319 322
320 323 ## Example: connect to the virtual host 'rabbitmqhost' on localhost as rabbitmq:
321 324 broker.url = amqp://rabbitmq:qewqew@localhost:5672/rabbitmqhost
322 325
323 326 celery.imports = kallithea.lib.celerylib.tasks
324 327 celery.accept.content = pickle
325 328 celery.result.backend = amqp
326 329 celery.result.dburi = amqp://
327 330 celery.result.serialier = json
328 331
329 332 #celery.send.task.error.emails = true
330 333 #celery.amqp.task.result.expires = 18000
331 334
332 335 celeryd.concurrency = 2
333 336 celeryd.max.tasks.per.child = 1
334 337
335 338 ## If true, tasks will never be sent to the queue, but executed locally instead.
336 339 celery.always.eager = false
337 340
338 341 ####################################
339 342 ### BEAKER CACHE ####
340 343 ####################################
341 344
342 345 #beaker.cache.data_dir = %(here)s/data/cache/data
343 346 beaker.cache.data_dir = %(here)s/../../data/test/cache/data
344 347 #beaker.cache.lock_dir = %(here)s/data/cache/lock
345 348 beaker.cache.lock_dir = %(here)s/../../data/test/cache/lock
346 349
347 350 beaker.cache.regions = short_term,long_term,sql_cache_short
348 351
349 352 beaker.cache.short_term.type = memory
350 353 beaker.cache.short_term.expire = 60
351 354 beaker.cache.short_term.key_length = 256
352 355
353 356 beaker.cache.long_term.type = memory
354 357 beaker.cache.long_term.expire = 36000
355 358 beaker.cache.long_term.key_length = 256
356 359
357 360 beaker.cache.sql_cache_short.type = memory
358 361 #beaker.cache.sql_cache_short.expire = 10
359 362 beaker.cache.sql_cache_short.expire = 1
360 363 beaker.cache.sql_cache_short.key_length = 256
361 364
362 365 ####################################
363 366 ### BEAKER SESSION ####
364 367 ####################################
365 368
366 369 ## Name of session cookie. Should be unique for a given host and path, even when running
367 370 ## on different ports. Otherwise, cookie sessions will be shared and messed up.
368 371 beaker.session.key = kallithea
369 372 ## Sessions should always only be accessible by the browser, not directly by JavaScript.
370 373 beaker.session.httponly = true
371 374 ## Session lifetime. 2592000 seconds is 30 days.
372 375 beaker.session.timeout = 2592000
373 376
374 377 ## Server secret used with HMAC to ensure integrity of cookies.
375 378 beaker.session.secret = {74e0cd75-b339-478b-b129-07dd221def1f}
376 379 ## Further, encrypt the data with AES.
377 380 #beaker.session.encrypt_key = <key_for_encryption>
378 381 #beaker.session.validate_key = <validation_key>
379 382
380 383 ## Type of storage used for the session, current types are
381 384 ## dbm, file, memcached, database, and memory.
382 385
383 386 ## File system storage of session data. (default)
384 387 #beaker.session.type = file
385 388
386 389 ## Cookie only, store all session data inside the cookie. Requires secure secrets.
387 390 #beaker.session.type = cookie
388 391
389 392 ## Database storage of session data.
390 393 #beaker.session.type = ext:database
391 394 #beaker.session.sa.url = postgresql://postgres:qwe@localhost/kallithea
392 395 #beaker.session.table_name = db_session
393 396
394 397 ############################
395 398 ## ERROR HANDLING SYSTEMS ##
396 399 ############################
397 400
398 401 ####################
399 402 ### [appenlight] ###
400 403 ####################
401 404
402 405 ## AppEnlight is tailored to work with Kallithea, see
403 406 ## http://appenlight.com for details how to obtain an account
404 407 ## you must install python package `appenlight_client` to make it work
405 408
406 409 ## appenlight enabled
407 410 appenlight = false
408 411
409 412 appenlight.server_url = https://api.appenlight.com
410 413 appenlight.api_key = YOUR_API_KEY
411 414
412 415 ## TWEAK AMOUNT OF INFO SENT HERE
413 416
414 417 ## enables 404 error logging (default False)
415 418 appenlight.report_404 = false
416 419
417 420 ## time in seconds after request is considered being slow (default 1)
418 421 appenlight.slow_request_time = 1
419 422
420 423 ## record slow requests in application
421 424 ## (needs to be enabled for slow datastore recording and time tracking)
422 425 appenlight.slow_requests = true
423 426
424 427 ## enable hooking to application loggers
425 428 #appenlight.logging = true
426 429
427 430 ## minimum log level for log capture
428 431 #appenlight.logging.level = WARNING
429 432
430 433 ## send logs only from erroneous/slow requests
431 434 ## (saves API quota for intensive logging)
432 435 appenlight.logging_on_error = false
433 436
434 437 ## list of additional keywords that should be grabbed from environ object
435 438 ## can be string with comma separated list of words in lowercase
436 439 ## (by default client will always send following info:
437 440 ## 'REMOTE_USER', 'REMOTE_ADDR', 'SERVER_NAME', 'CONTENT_TYPE' + all keys that
438 441 ## start with HTTP* this list be extended with additional keywords here
439 442 appenlight.environ_keys_whitelist =
440 443
441 444 ## list of keywords that should be blanked from request object
442 445 ## can be string with comma separated list of words in lowercase
443 446 ## (by default client will always blank keys that contain following words
444 447 ## 'password', 'passwd', 'pwd', 'auth_tkt', 'secret', 'csrf'
445 448 ## this list be extended with additional keywords set here
446 449 appenlight.request_keys_blacklist =
447 450
448 451 ## list of namespaces that should be ignores when gathering log entries
449 452 ## can be string with comma separated list of namespaces
450 453 ## (by default the client ignores own entries: appenlight_client.client)
451 454 appenlight.log_namespace_blacklist =
452 455
453 456 ################
454 457 ### [sentry] ###
455 458 ################
456 459
457 460 ## sentry is a alternative open source error aggregator
458 461 ## you must install python packages `sentry` and `raven` to enable
459 462
460 463 sentry.dsn = YOUR_DNS
461 464 sentry.servers =
462 465 sentry.name =
463 466 sentry.key =
464 467 sentry.public_key =
465 468 sentry.secret_key =
466 469 sentry.project =
467 470 sentry.site =
468 471 sentry.include_paths =
469 472 sentry.exclude_paths =
470 473
471 474 ################################################################################
472 475 ## WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT* ##
473 476 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
474 477 ## execute malicious code after an exception is raised. ##
475 478 ################################################################################
476 479 set debug = false
477 480
478 481 ##################################
479 482 ### LOGVIEW CONFIG ###
480 483 ##################################
481 484
482 485 logview.sqlalchemy = #faa
483 486 logview.pylons.templating = #bfb
484 487 logview.pylons.util = #eee
485 488
486 489 #########################################################
487 490 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
488 491 #########################################################
489 492
490 493 # SQLITE [default]
491 494 #sqlalchemy.url = sqlite:///%(here)s/kallithea.db?timeout=60
492 495 sqlalchemy.url = sqlite:///%(here)s/kallithea_test.sqlite
493 496
494 497 # POSTGRESQL
495 498 #sqlalchemy.url = postgresql://user:pass@localhost/kallithea
496 499
497 500 # MySQL
498 501 #sqlalchemy.url = mysql://user:pass@localhost/kallithea?charset=utf8
499 502
500 503 # see sqlalchemy docs for others
501 504
502 505 sqlalchemy.echo = false
503 506 sqlalchemy.pool_recycle = 3600
504 507
505 508 ################################
506 509 ### ALEMBIC CONFIGURATION ####
507 510 ################################
508 511
509 512 [alembic]
510 513 script_location = kallithea:alembic
511 514
512 515 ################################
513 516 ### LOGGING CONFIGURATION ####
514 517 ################################
515 518
516 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 522 [handlers]
520 523 keys = console, console_sql
521 524
522 525 [formatters]
523 526 keys = generic, color_formatter, color_formatter_sql
524 527
525 528 #############
526 529 ## LOGGERS ##
527 530 #############
528 531
529 532 [logger_root]
530 533 level = NOTSET
531 534 handlers = console
532 535
533 536 [logger_routes]
534 537 level = DEBUG
535 538 handlers =
536 539 qualname = routes.middleware
537 540 ## "level = DEBUG" logs the route matched and routing variables.
538 541 propagate = 1
539 542
540 543 [logger_beaker]
541 544 level = DEBUG
542 545 handlers =
543 546 qualname = beaker.container
544 547 propagate = 1
545 548
546 549 [logger_templates]
547 550 level = INFO
548 551 handlers =
549 552 qualname = pylons.templating
550 553 propagate = 1
551 554
552 555 [logger_kallithea]
553 556 level = DEBUG
554 557 handlers =
555 558 qualname = kallithea
556 559 propagate = 1
557 560
561 [logger_gearbox]
562 level = DEBUG
563 handlers =
564 qualname = gearbox
565 propagate = 1
566
558 567 [logger_sqlalchemy]
559 568 level = INFO
560 569 handlers = console_sql
561 570 qualname = sqlalchemy.engine
562 571 propagate = 0
563 572
564 573 [logger_whoosh_indexer]
565 574 level = DEBUG
566 575 handlers =
567 576 qualname = whoosh_indexer
568 577 propagate = 1
569 578
570 579 ##############
571 580 ## HANDLERS ##
572 581 ##############
573 582
574 583 [handler_console]
575 584 class = StreamHandler
576 585 args = (sys.stderr,)
577 586 #level = INFO
578 587 level = DEBUG
579 588 #formatter = generic
580 589 formatter = color_formatter
581 590
582 591 [handler_console_sql]
583 592 class = StreamHandler
584 593 args = (sys.stderr,)
585 594 level = WARN
586 595 #formatter = generic
587 596 formatter = color_formatter_sql
588 597
589 598 ################
590 599 ## FORMATTERS ##
591 600 ################
592 601
593 602 [formatter_generic]
594 603 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
595 604 datefmt = %Y-%m-%d %H:%M:%S
596 605
597 606 [formatter_color_formatter]
598 607 class = kallithea.lib.colored_formatter.ColorFormatter
599 608 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
600 609 datefmt = %Y-%m-%d %H:%M:%S
601 610
602 611 [formatter_color_formatter_sql]
603 612 class = kallithea.lib.colored_formatter.ColorFormatterSql
604 613 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
605 614 datefmt = %Y-%m-%d %H:%M:%S
@@ -1,121 +1,121 b''
1 1 #!/bin/sh -e
2 2
3 3 if [ $# -lt 2 ] || [ $# -gt 3 ]; then
4 4 cat >&2 <<EOD
5 5 usage: $0 CONFIG_FILE FROM_REV [TO_REV]
6 6
7 7 Runs a database migration from FROM_REV to TO_REV (default: current
8 8 working directory parent), using the specified CONFIG_FILE (.ini file).
9 9
10 10 Test is run using a clean Kallithea install, in a temporary virtual
11 11 environment. FROM_REV and (optional) TO_REV should be Mercurial revision
12 12 identifiers (e.g. changeset hash or a version number tag). The working
13 13 directory is not touched, but the database referenced in the config file
14 14 will be (re)created.
15 15
16 16 Only SQLite is available out of the box; for MySQL or PostgreSQL, set
17 17 the EXTRA environment variable to the required package(s), and it'll
18 18 be installed in the virtual environment. (E.g. EXTRA=MySQL-python or
19 19 EXTRA=psycopg2.)
20 20
21 21 The temporary directory is not removed, allowing follow-up examination
22 22 of the upgrade results. It is, however, created in /tmp by default,
23 23 which many Linux distributions automatically clean at regular intervals.
24 24 EOD
25 25 exit 1
26 26 fi
27 27
28 28 config_file=$(readlink -f "$1")
29 29 from_rev=$2
30 30 to_rev=$3
31 31 source_repo=$(dirname "$(dirname "$(readlink -f "$0")")")
32 32
33 33 announce() {
34 34 echo
35 35 echo "$1"
36 36 echo
37 37 }
38 38
39 39 quiet_if_ok() (
40 40 local output
41 41 local st
42 42 set +e
43 43 output=$("$@" < /dev/null 2>&1)
44 44 st=$?
45 45 if [ $st -ne 0 ]; then
46 46 echo "$output" >&2
47 47 echo "Command $@ returned exit status $st." >&2
48 48 exit 1
49 49 fi
50 50 )
51 51
52 52 HG() {
53 53 "${HG:-hg}" --repository "$source_repo" "$@"
54 54 }
55 55
56 56 # If upgrading to "current revision", warn if working directory is dirty.
57 57 if [ ! "$to_rev" ] && [ "$(HG status -mard)" ]; then
58 58 announce "Warning: Uncommitted changes in working directory will be ignored!"
59 59 fi
60 60
61 61 from_rev_hash=$(HG id --id --rev "${from_rev:-.}")
62 62 to_rev_hash=$(HG id --id --rev "${to_rev:-.}")
63 63 temp=$(readlink -f "$(mktemp --tmpdir -d 'dbmigrate-test.XXXXXX')")
64 64
65 65 cat <<EOD
66 66 Config file: $config_file
67 67 EOD
68 68 sed -n -e 's/^sqlalchemy\.url *= */Database URL: /p' "$config_file"
69 69 cat <<EOD
70 70 Working dir: $temp
71 71 Repository: $source_repo
72 72 Upgrade from: $from_rev_hash (${from_rev:-current})
73 73 Upgrade to: $to_rev_hash (${to_rev:-current})
74 74 Extra packages: ${EXTRA:-(none)}
75 75 EOD
76 76
77 77 mkdir "$temp/repos" # empty
78 78
79 79 # Enable caching for old pip versions (this will cache the pip upgrade)
80 80 # Newer pip versions cache automatically, and don't use this variable.
81 81 if [ ! "$PIP_DOWNLOAD_CACHE" ]; then
82 82 export PIP_DOWNLOAD_CACHE=$HOME/.cache/pip/legacy
83 83 fi
84 84
85 85 install_kallithea() {
86 86 local prefix=$1
87 87 local rev=$2
88 88
89 89 announce "Installing Kallithea $rev in $prefix..."
90 90
91 91 "${VIRTUALENV:-virtualenv}" --quiet "$prefix-env"
92 92 HG archive --rev "$rev" "$prefix"
93 93
94 94 (
95 95 cd "$prefix"
96 96 . "$prefix-env/bin/activate"
97 97 pip install --quiet --upgrade pip setuptools mercurial $EXTRA
98 98 pip install --quiet -e .
99 99 )
100 100 }
101 101
102 102 install_kallithea "$temp/from" "$from_rev_hash"
103 103 (
104 104 cd "$temp/from"
105 105 . "$temp/from-env/bin/activate"
106 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 108 alembic -c "$config_file" current -v
109 109 )
110 110
111 111 install_kallithea "$temp/to" "$to_rev_hash"
112 112 (
113 113 cd "$temp/to"
114 114 . "$temp/to-env/bin/activate"
115 115
116 116 announce "Commencing database upgrade from shown Alembic revision to head..."
117 117 alembic -c "$config_file" current -v
118 118 alembic -c "$config_file" upgrade head
119 119 announce "Upgrade complete, now at the shown Alembic revision:"
120 120 alembic -c "$config_file" current -v
121 121 )
@@ -1,171 +1,170 b''
1 1 #!/usr/bin/env python2
2 2 # -*- coding: utf-8 -*-
3 3 import os
4 4 import sys
5 5 import platform
6 6
7 7 if sys.version_info < (2, 6) or sys.version_info >= (3,):
8 8 raise Exception('Kallithea requires python 2.6 or 2.7')
9 9
10 10
11 11 here = os.path.abspath(os.path.dirname(__file__))
12 12
13 13
14 14 def _get_meta_var(name, data, callback_handler=None):
15 15 import re
16 16 matches = re.compile(r'(?:%s)\s*=\s*(.*)' % name).search(data)
17 17 if matches:
18 18 if not callable(callback_handler):
19 19 callback_handler = lambda v: v
20 20
21 21 return callback_handler(eval(matches.groups()[0]))
22 22
23 23 _meta = open(os.path.join(here, 'kallithea', '__init__.py'), 'rb')
24 24 _metadata = _meta.read()
25 25 _meta.close()
26 26
27 27 callback = lambda V: ('.'.join(map(str, V[:3])) + '.'.join(V[3:]))
28 28 __version__ = _get_meta_var('VERSION', _metadata, callback)
29 29 __license__ = _get_meta_var('__license__', _metadata)
30 30 __author__ = _get_meta_var('__author__', _metadata)
31 31 __url__ = _get_meta_var('__url__', _metadata)
32 32 # defines current platform
33 33 __platform__ = platform.system()
34 34
35 35 is_windows = __platform__ in ['Windows']
36 36
37 37 requirements = [
38 38 "alembic>=0.8.0,<0.9",
39 "GearBox<1",
39 40 "waitress>=0.8.8,<1.0",
40 41 "webob>=1.7,<2",
41 42 "Pylons>=1.0.0,<=1.0.2",
42 43 "Beaker>=1.7.0,<2",
43 44 "WebHelpers==1.3",
44 45 "formencode>=1.2.4,<=1.2.6",
45 46 "SQLAlchemy>=1.0,<1.1",
46 47 "Mako>=0.9.0,<=1.0.0",
47 48 "pygments>=1.5",
48 49 "whoosh>=2.5.0,<=2.5.7",
49 50 "celery>=3.1,<3.2",
50 51 "babel>=0.9.6,<2.4",
51 52 "python-dateutil>=1.5.0,<2.0.0",
52 53 "markdown==2.2.1",
53 54 "docutils>=0.8.1",
54 55 "URLObject==2.3.4",
55 56 "Routes==1.13",
56 57 "dulwich>=0.14.1",
57 58 "mercurial>=2.9,<4.2",
58 59 ]
59 60
60 61 if sys.version_info < (2, 7):
61 62 requirements.append("importlib==1.0.1")
62 63 requirements.append("argparse")
63 64
64 65 if not is_windows:
65 66 requirements.append("bcrypt>=3.1.0")
66 67
67 68 dependency_links = [
68 69 ]
69 70
70 71 classifiers = [
71 72 'Development Status :: 4 - Beta',
72 73 'Environment :: Web Environment',
73 74 'Framework :: Pylons',
74 75 'Intended Audience :: Developers',
75 76 'License :: OSI Approved :: GNU General Public License (GPL)',
76 77 'Operating System :: OS Independent',
77 78 'Programming Language :: Python',
78 79 'Programming Language :: Python :: 2.6',
79 80 'Programming Language :: Python :: 2.7',
80 81 'Topic :: Software Development :: Version Control',
81 82 ]
82 83
83 84
84 85 # additional files from project that goes somewhere in the filesystem
85 86 # relative to sys.prefix
86 87 data_files = []
87 88
88 89 description = ('Kallithea is a fast and powerful management tool '
89 90 'for Mercurial and Git with a built in push/pull server, '
90 91 'full text search and code-review.')
91 92
92 93 keywords = ' '.join([
93 94 'kallithea', 'mercurial', 'git', 'code review',
94 95 'repo groups', 'ldap', 'repository management', 'hgweb replacement',
95 96 'hgwebdir', 'gitweb replacement', 'serving hgweb',
96 97 ])
97 98
98 99 # long description
99 100 README_FILE = 'README.rst'
100 101 try:
101 102 long_description = open(README_FILE).read()
102 103 except IOError as err:
103 104 sys.stderr.write(
104 105 "[WARNING] Cannot find file specified as long_description (%s)\n"
105 106 % README_FILE
106 107 )
107 108 long_description = description
108 109
109 110 import setuptools
110 111
111 112 # monkey patch setuptools to use distutils owner/group functionality
112 113 from setuptools.command import sdist
113 114 sdist_org = sdist.sdist
114 115 class sdist_new(sdist_org):
115 116 def initialize_options(self):
116 117 sdist_org.initialize_options(self)
117 118 self.owner = self.group = 'root'
118 119 sdist.sdist = sdist_new
119 120
120 121 packages = setuptools.find_packages(exclude=['ez_setup'])
121 122
122 123 setuptools.setup(
123 124 name='Kallithea',
124 125 version=__version__,
125 126 description=description,
126 127 long_description=long_description,
127 128 keywords=keywords,
128 129 license=__license__,
129 130 author=__author__,
130 131 author_email='kallithea@sfconservancy.org',
131 132 dependency_links=dependency_links,
132 133 url=__url__,
133 134 install_requires=requirements,
134 135 classifiers=classifiers,
135 setup_requires=['PasteScript>=1.6.3'],
136 136 data_files=data_files,
137 137 packages=packages,
138 138 include_package_data=True,
139 139 message_extractors={'kallithea': [
140 140 ('**.py', 'python', None),
141 141 ('templates/**.mako', 'mako', {'input_encoding': 'utf-8'}),
142 142 ('templates/**.html', 'mako', {'input_encoding': 'utf-8'}),
143 143 ('public/**', 'ignore', None)]},
144 144 zip_safe=False,
145 paster_plugins=['PasteScript', 'Pylons'],
146 145 entry_points="""
147 146 [console_scripts]
148 147 kallithea-api = kallithea.bin.kallithea_api:main
149 148 kallithea-gist = kallithea.bin.kallithea_gist:main
150 149 kallithea-config = kallithea.bin.kallithea_config:main
151 150
152 151 [paste.app_factory]
153 152 main = kallithea.config.middleware:make_app
154 153
155 154 [paste.app_install]
156 155 main = pylons.util:PylonsInstaller
157 156
158 [paste.global_paster_command]
157 [gearbox.commands]
159 158 setup-db=kallithea.lib.paster_commands.setup_db:Command
160 159 cleanup-repos=kallithea.lib.paster_commands.cleanup:Command
161 160 update-repoinfo=kallithea.lib.paster_commands.update_repoinfo:Command
162 161 make-rcext=kallithea.lib.paster_commands.make_rcextensions:Command
163 162 repo-scan=kallithea.lib.paster_commands.repo_scan:Command
164 163 cache-keys=kallithea.lib.paster_commands.cache_keys:Command
165 164 ishell=kallithea.lib.paster_commands.ishell:Command
166 165 make-index=kallithea.lib.paster_commands.make_index:Command
167 166 upgrade-db=kallithea.lib.dbmigrate:UpgradeDb
168 167 celeryd=kallithea.lib.paster_commands.celeryd:Command
169 168 install-iis=kallithea.lib.paster_commands.install_iis:Command
170 169 """,
171 170 )
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now