##// END OF EJS Templates
inifile: new implementation of setting updates to optimize reuse of comments and append location...
Mads Kiilerich -
r8226:238885ea default
parent child Browse files
Show More
@@ -1,514 +1,513 b''
1 ###################################################################################
1 ###################################################################################
2 ###################################################################################
2 ###################################################################################
3 ## Kallithea config file generated with kallithea-config ##
3 ## Kallithea config file generated with kallithea-config ##
4 ## ##
4 ## ##
5 ## The %(here)s variable will be replaced with the parent directory of this file ##
5 ## The %(here)s variable will be replaced with the parent directory of this file ##
6 ###################################################################################
6 ###################################################################################
7 ###################################################################################
7 ###################################################################################
8
8
9 [DEFAULT]
9 [DEFAULT]
10
10
11 ################################################################################
11 ################################################################################
12 ## Email settings ##
12 ## Email settings ##
13 ## ##
13 ## ##
14 ## Refer to the documentation ("Email settings") for more details. ##
14 ## Refer to the documentation ("Email settings") for more details. ##
15 ## ##
15 ## ##
16 ## It is recommended to use a valid sender address that passes access ##
16 ## It is recommended to use a valid sender address that passes access ##
17 ## validation and spam filtering in mail servers. ##
17 ## validation and spam filtering in mail servers. ##
18 ################################################################################
18 ################################################################################
19
19
20 ## 'From' header for application emails. You can optionally add a name.
20 ## 'From' header for application emails. You can optionally add a name.
21 ## Default:
21 ## Default:
22 #app_email_from = Kallithea
22 #app_email_from = Kallithea
23 ## Examples:
23 ## Examples:
24 #app_email_from = Kallithea <kallithea-noreply@example.com>
24 #app_email_from = Kallithea <kallithea-noreply@example.com>
25 #app_email_from = kallithea-noreply@example.com
25 #app_email_from = kallithea-noreply@example.com
26
26
27 ## Subject prefix for application emails.
27 ## Subject prefix for application emails.
28 ## A space between this prefix and the real subject is automatically added.
28 ## A space between this prefix and the real subject is automatically added.
29 ## Default:
29 ## Default:
30 #email_prefix =
30 #email_prefix =
31 ## Example:
31 ## Example:
32 #email_prefix = [Kallithea]
32 #email_prefix = [Kallithea]
33
33
34 ## Recipients for error emails and fallback recipients of application mails.
34 ## Recipients for error emails and fallback recipients of application mails.
35 ## Multiple addresses can be specified, comma-separated.
35 ## Multiple addresses can be specified, comma-separated.
36 ## Only addresses are allowed, do not add any name part.
36 ## Only addresses are allowed, do not add any name part.
37 ## Default:
37 ## Default:
38 #email_to =
38 #email_to =
39 ## Examples:
39 ## Examples:
40 #email_to = admin@example.com
40 #email_to = admin@example.com
41 #email_to = admin@example.com,another_admin@example.com
41 #email_to = admin@example.com,another_admin@example.com
42 email_to =
42 email_to =
43
43
44 ## 'From' header for error emails. You can optionally add a name.
44 ## 'From' header for error emails. You can optionally add a name.
45 ## Default: (none)
45 ## Default: (none)
46 ## Examples:
46 ## Examples:
47 #error_email_from = Kallithea Errors <kallithea-noreply@example.com>
47 #error_email_from = Kallithea Errors <kallithea-noreply@example.com>
48 #error_email_from = kallithea_errors@example.com
48 #error_email_from = kallithea_errors@example.com
49 error_email_from =
49 error_email_from =
50
50
51 ## SMTP server settings
51 ## SMTP server settings
52 ## If specifying credentials, make sure to use secure connections.
52 ## If specifying credentials, make sure to use secure connections.
53 ## Default: Send unencrypted unauthenticated mails to the specified smtp_server.
53 ## Default: Send unencrypted unauthenticated mails to the specified smtp_server.
54 ## For "SSL", use smtp_use_ssl = true and smtp_port = 465.
54 ## For "SSL", use smtp_use_ssl = true and smtp_port = 465.
55 ## For "STARTTLS", use smtp_use_tls = true and smtp_port = 587.
55 ## For "STARTTLS", use smtp_use_tls = true and smtp_port = 587.
56 smtp_server =
56 smtp_server =
57 smtp_username =
57 smtp_username =
58 smtp_password =
58 smtp_password =
59 smtp_port =
59 smtp_port =
60 smtp_use_ssl = false
60 smtp_use_ssl = false
61 smtp_use_tls = false
61 smtp_use_tls = false
62
62
63 ## Entry point for 'gearbox serve'
63 ## Entry point for 'gearbox serve'
64 [server:main]
64 [server:main]
65 #host = 127.0.0.1
65 #host = 127.0.0.1
66 host = 0.0.0.0
66 host = 0.0.0.0
67 port = 5000
67 port = 5000
68
68
69 ## WAITRESS ##
69 ## WAITRESS ##
70 use = egg:waitress#main
70 use = egg:waitress#main
71 ## number of worker threads
71 ## number of worker threads
72 threads = 1
72 threads = 1
73 ## MAX BODY SIZE 100GB
73 ## MAX BODY SIZE 100GB
74 max_request_body_size = 107374182400
74 max_request_body_size = 107374182400
75 ## use poll instead of select, fixes fd limits, may not work on old
75 ## use poll instead of select, fixes fd limits, may not work on old
76 ## windows systems.
76 ## windows systems.
77 #asyncore_use_poll = True
77 #asyncore_use_poll = True
78
78
79 ## middleware for hosting the WSGI application under a URL prefix
79 ## middleware for hosting the WSGI application under a URL prefix
80 #[filter:proxy-prefix]
80 #[filter:proxy-prefix]
81 #use = egg:PasteDeploy#prefix
81 #use = egg:PasteDeploy#prefix
82 #prefix = /<your-prefix>
82 #prefix = /<your-prefix>
83
83
84 [app:main]
84 [app:main]
85 use = egg:kallithea
85 use = egg:kallithea
86 ## enable proxy prefix middleware
86 ## enable proxy prefix middleware
87 #filter-with = proxy-prefix
87 #filter-with = proxy-prefix
88
88
89 full_stack = true
89 full_stack = true
90 static_files = true
90 static_files = true
91
91
92 ## Internationalization (see setup documentation for details)
92 ## Internationalization (see setup documentation for details)
93 ## By default, the languages requested by the browser are used if available, with English as default.
93 ## By default, the languages requested by the browser are used if available, with English as default.
94 ## Set i18n.enabled=false to disable automatic language choice.
94 ## Set i18n.enabled=false to disable automatic language choice.
95 #i18n.enabled = true
95 #i18n.enabled = true
96 ## To Force a language, set i18n.enabled=false and specify the language in i18n.lang.
96 ## To Force a language, set i18n.enabled=false and specify the language in i18n.lang.
97 ## Valid values are the names of subdirectories in kallithea/i18n with a LC_MESSAGES/kallithea.mo
97 ## Valid values are the names of subdirectories in kallithea/i18n with a LC_MESSAGES/kallithea.mo
98 #i18n.lang = en
98 #i18n.lang = en
99
99
100 cache_dir = %(here)s/data
100 cache_dir = %(here)s/data
101 index_dir = %(here)s/data/index
101 index_dir = %(here)s/data/index
102
102
103 ## uncomment and set this path to use archive download cache
103 ## uncomment and set this path to use archive download cache
104 archive_cache_dir = %(here)s/tarballcache
104 archive_cache_dir = %(here)s/tarballcache
105
105
106 ## change this to unique ID for security
106 ## change this to unique ID for security
107 #app_instance_uuid = VERY-SECRET
107 #app_instance_uuid = VERY-SECRET
108 app_instance_uuid = development-not-secret
108 app_instance_uuid = development-not-secret
109
109
110 ## cut off limit for large diffs (size in bytes)
110 ## cut off limit for large diffs (size in bytes)
111 cut_off_limit = 256000
111 cut_off_limit = 256000
112
112
113 ## force https in Kallithea, fixes https redirects, assumes it's always https
113 ## force https in Kallithea, fixes https redirects, assumes it's always https
114 force_https = false
114 force_https = false
115
115
116 ## use Strict-Transport-Security headers
116 ## use Strict-Transport-Security headers
117 use_htsts = false
117 use_htsts = false
118
118
119 ## number of commits stats will parse on each iteration
119 ## number of commits stats will parse on each iteration
120 commit_parse_limit = 25
120 commit_parse_limit = 25
121
121
122 ## Path to Python executable to be used for git hooks.
122 ## Path to Python executable to be used for git hooks.
123 ## This value will be written inside the git hook scripts as the text
123 ## This value will be written inside the git hook scripts as the text
124 ## after '#!' (shebang). When empty or not defined, the value of
124 ## after '#!' (shebang). When empty or not defined, the value of
125 ## 'sys.executable' at the time of installation of the git hooks is
125 ## 'sys.executable' at the time of installation of the git hooks is
126 ## used, which is correct in many cases but for example not when using uwsgi.
126 ## used, which is correct in many cases but for example not when using uwsgi.
127 ## If you change this setting, you should reinstall the Git hooks via
127 ## If you change this setting, you should reinstall the Git hooks via
128 ## Admin > Settings > Remap and Rescan.
128 ## Admin > Settings > Remap and Rescan.
129 #git_hook_interpreter = /srv/kallithea/venv/bin/python3
129 #git_hook_interpreter = /srv/kallithea/venv/bin/python3
130
130
131 ## path to git executable
131 ## path to git executable
132 git_path = git
132 git_path = git
133
133
134 ## git rev filter option, --all is the default filter, if you need to
134 ## git rev filter option, --all is the default filter, if you need to
135 ## hide all refs in changelog switch this to --branches --tags
135 ## hide all refs in changelog switch this to --branches --tags
136 #git_rev_filter = --branches --tags
136 #git_rev_filter = --branches --tags
137
137
138 ## RSS feed options
138 ## RSS feed options
139 rss_cut_off_limit = 256000
139 rss_cut_off_limit = 256000
140 rss_items_per_page = 10
140 rss_items_per_page = 10
141 rss_include_diff = false
141 rss_include_diff = false
142
142
143 ## options for showing and identifying changesets
143 ## options for showing and identifying changesets
144 show_sha_length = 12
144 show_sha_length = 12
145 show_revision_number = false
145 show_revision_number = false
146
146
147 ## Canonical URL to use when creating full URLs in UI and texts.
147 ## Canonical URL to use when creating full URLs in UI and texts.
148 ## Useful when the site is available under different names or protocols.
148 ## Useful when the site is available under different names or protocols.
149 ## Defaults to what is provided in the WSGI environment.
149 ## Defaults to what is provided in the WSGI environment.
150 #canonical_url = https://kallithea.example.com/repos
150 #canonical_url = https://kallithea.example.com/repos
151
151
152 ## gist URL alias, used to create nicer urls for gist. This should be an
152 ## gist URL alias, used to create nicer urls for gist. This should be an
153 ## url that does rewrites to _admin/gists/<gistid>.
153 ## url that does rewrites to _admin/gists/<gistid>.
154 ## example: http://gist.example.com/{gistid}. Empty means use the internal
154 ## example: http://gist.example.com/{gistid}. Empty means use the internal
155 ## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid>
155 ## Kallithea url, ie. http[s]://kallithea.example.com/_admin/gists/<gistid>
156 gist_alias_url =
156 gist_alias_url =
157
157
158 ## default encoding used to convert from and to unicode
158 ## default encoding used to convert from and to unicode
159 ## can be also a comma separated list of encoding in case of mixed encodings
159 ## can be also a comma separated list of encoding in case of mixed encodings
160 default_encoding = utf-8
160 default_encoding = utf-8
161
161
162 ## Set Mercurial encoding, similar to setting HGENCODING before launching Kallithea
162 ## Set Mercurial encoding, similar to setting HGENCODING before launching Kallithea
163 hgencoding = utf-8
163 hgencoding = utf-8
164
164
165 ## issue tracker for Kallithea (leave blank to disable, absent for default)
165 ## issue tracker for Kallithea (leave blank to disable, absent for default)
166 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
166 #bugtracker = https://bitbucket.org/conservancy/kallithea/issues
167
167
168 ## issue tracking mapping for commit messages, comments, PR descriptions, ...
168 ## issue tracking mapping for commit messages, comments, PR descriptions, ...
169 ## Refer to the documentation ("Integration with issue trackers") for more details.
169 ## Refer to the documentation ("Integration with issue trackers") for more details.
170
170
171 ## regular expression to match issue references
171 ## regular expression to match issue references
172 ## This pattern may/should contain parenthesized groups, that can
172 ## This pattern may/should contain parenthesized groups, that can
173 ## be referred to in issue_server_link or issue_sub using Python backreferences
173 ## be referred to in issue_server_link or issue_sub using Python backreferences
174 ## (e.g. \1, \2, ...). You can also create named groups with '(?P<groupname>)'.
174 ## (e.g. \1, \2, ...). You can also create named groups with '(?P<groupname>)'.
175 ## To require mandatory whitespace before the issue pattern, use:
175 ## To require mandatory whitespace before the issue pattern, use:
176 ## (?:^|(?<=\s)) before the actual pattern, and for mandatory whitespace
176 ## (?:^|(?<=\s)) before the actual pattern, and for mandatory whitespace
177 ## behind the issue pattern, use (?:$|(?=\s)) after the actual pattern.
177 ## behind the issue pattern, use (?:$|(?=\s)) after the actual pattern.
178
178
179 issue_pat = #(\d+)
179 issue_pat = #(\d+)
180
180
181 ## server url to the issue
181 ## server url to the issue
182 ## This pattern may/should contain backreferences to parenthesized groups in issue_pat.
182 ## This pattern may/should contain backreferences to parenthesized groups in issue_pat.
183 ## A backreference can be \1, \2, ... or \g<groupname> if you specified a named group
183 ## A backreference can be \1, \2, ... or \g<groupname> if you specified a named group
184 ## called 'groupname' in issue_pat.
184 ## called 'groupname' in issue_pat.
185 ## The special token {repo} is replaced with the full repository name
185 ## The special token {repo} is replaced with the full repository name
186 ## including repository groups, while {repo_name} is replaced with just
186 ## including repository groups, while {repo_name} is replaced with just
187 ## the name of the repository.
187 ## the name of the repository.
188
188
189 issue_server_link = https://issues.example.com/{repo}/issue/\1
189 issue_server_link = https://issues.example.com/{repo}/issue/\1
190
190
191 ## substitution pattern to use as the link text
191 ## substitution pattern to use as the link text
192 ## If issue_sub is empty, the text matched by issue_pat is retained verbatim
192 ## If issue_sub is empty, the text matched by issue_pat is retained verbatim
193 ## for the link text. Otherwise, the link text is that of issue_sub, with any
193 ## for the link text. Otherwise, the link text is that of issue_sub, with any
194 ## backreferences to groups in issue_pat replaced.
194 ## backreferences to groups in issue_pat replaced.
195
195
196 issue_sub =
196 issue_sub =
197
197
198 ## issue_pat, issue_server_link and issue_sub can have suffixes to specify
198 ## issue_pat, issue_server_link and issue_sub can have suffixes to specify
199 ## multiple patterns, to other issues server, wiki or others
199 ## multiple patterns, to other issues server, wiki or others
200 ## below an example how to create a wiki pattern
200 ## below an example how to create a wiki pattern
201 ## wiki-some-id -> https://wiki.example.com/some-id
201 ## wiki-some-id -> https://wiki.example.com/some-id
202
202
203 #issue_pat_wiki = wiki-(\S+)
203 #issue_pat_wiki = wiki-(\S+)
204 #issue_server_link_wiki = https://wiki.example.com/\1
204 #issue_server_link_wiki = https://wiki.example.com/\1
205 #issue_sub_wiki = WIKI-\1
205 #issue_sub_wiki = WIKI-\1
206
206
207 ## alternative return HTTP header for failed authentication. Default HTTP
207 ## alternative return HTTP header for failed authentication. Default HTTP
208 ## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
208 ## response is 401 HTTPUnauthorized. Currently Mercurial clients have trouble with
209 ## handling that. Set this variable to 403 to return HTTPForbidden
209 ## handling that. Set this variable to 403 to return HTTPForbidden
210 auth_ret_code =
210 auth_ret_code =
211
211
212 ## allows to change the repository location in settings page
212 ## allows to change the repository location in settings page
213 allow_repo_location_change = True
213 allow_repo_location_change = True
214
214
215 ## allows to setup custom hooks in settings page
215 ## allows to setup custom hooks in settings page
216 allow_custom_hooks_settings = True
216 allow_custom_hooks_settings = True
217
217
218 ## extra extensions for indexing, space separated and without the leading '.'.
218 ## extra extensions for indexing, space separated and without the leading '.'.
219 #index.extensions =
219 #index.extensions =
220 # gemfile
220 # gemfile
221 # lock
221 # lock
222
222
223 ## extra filenames for indexing, space separated
223 ## extra filenames for indexing, space separated
224 #index.filenames =
224 #index.filenames =
225 # .dockerignore
225 # .dockerignore
226 # .editorconfig
226 # .editorconfig
227 # INSTALL
227 # INSTALL
228 # CHANGELOG
228 # CHANGELOG
229
229
230 ####################################
230 ####################################
231 ### SSH CONFIG ####
231 ### SSH CONFIG ####
232 ####################################
232 ####################################
233
233
234 ## SSH is disabled by default, until an Administrator decides to enable it.
234 ## SSH is disabled by default, until an Administrator decides to enable it.
235 ssh_enabled = false
235 ssh_enabled = false
236
236
237 ## File where users' SSH keys will be stored *if* ssh_enabled is true.
237 ## File where users' SSH keys will be stored *if* ssh_enabled is true.
238 #ssh_authorized_keys = /home/kallithea/.ssh/authorized_keys
238 #ssh_authorized_keys = /home/kallithea/.ssh/authorized_keys
239
239
240 ## Path to be used in ssh_authorized_keys file to invoke kallithea-cli with ssh-serve.
240 ## Path to be used in ssh_authorized_keys file to invoke kallithea-cli with ssh-serve.
241 #kallithea_cli_path = /srv/kallithea/venv/bin/kallithea-cli
241 #kallithea_cli_path = /srv/kallithea/venv/bin/kallithea-cli
242
242
243 ## Locale to be used in the ssh-serve command.
243 ## Locale to be used in the ssh-serve command.
244 ## This is needed because an SSH client may try to use its own locale
244 ## This is needed because an SSH client may try to use its own locale
245 ## settings, which may not be available on the server.
245 ## settings, which may not be available on the server.
246 ## See `locale -a` for valid values on this system.
246 ## See `locale -a` for valid values on this system.
247 #ssh_locale = C.UTF-8
247 #ssh_locale = C.UTF-8
248
248
249 ####################################
249 ####################################
250 ### CELERY CONFIG ####
250 ### CELERY CONFIG ####
251 ####################################
251 ####################################
252
252
253 ## Note: Celery doesn't support Windows.
253 ## Note: Celery doesn't support Windows.
254 use_celery = false
254 use_celery = false
255
255
256 ## Celery config settings from https://docs.celeryproject.org/en/4.4.0/userguide/configuration.html prefixed with 'celery.'.
256 ## Celery config settings from https://docs.celeryproject.org/en/4.4.0/userguide/configuration.html prefixed with 'celery.'.
257
257
258 ## Example: use the message queue on the local virtual host 'kallitheavhost' as the RabbitMQ user 'kallithea':
258 ## Example: use the message queue on the local virtual host 'kallitheavhost' as the RabbitMQ user 'kallithea':
259 celery.broker_url = amqp://kallithea:thepassword@localhost:5672/kallitheavhost
259 celery.broker_url = amqp://kallithea:thepassword@localhost:5672/kallitheavhost
260
260
261 celery.result.backend = db+sqlite:///celery-results.db
261 celery.result.backend = db+sqlite:///celery-results.db
262
262
263 #celery.amqp.task.result.expires = 18000
263 #celery.amqp.task.result.expires = 18000
264
264
265 celery.worker_concurrency = 2
265 celery.worker_concurrency = 2
266 celery.worker_max_tasks_per_child = 1
266 celery.worker_max_tasks_per_child = 1
267
267
268 ## If true, tasks will never be sent to the queue, but executed locally instead.
268 ## If true, tasks will never be sent to the queue, but executed locally instead.
269 celery.task_always_eager = false
269 celery.task_always_eager = false
270
270
271 ####################################
271 ####################################
272 ### BEAKER CACHE ####
272 ### BEAKER CACHE ####
273 ####################################
273 ####################################
274
274
275 beaker.cache.data_dir = %(here)s/data/cache/data
275 beaker.cache.data_dir = %(here)s/data/cache/data
276 beaker.cache.lock_dir = %(here)s/data/cache/lock
276 beaker.cache.lock_dir = %(here)s/data/cache/lock
277
277
278 beaker.cache.regions = long_term,long_term_file
278 beaker.cache.regions = long_term,long_term_file
279
279
280 beaker.cache.long_term.type = memory
280 beaker.cache.long_term.type = memory
281 beaker.cache.long_term.expire = 36000
281 beaker.cache.long_term.expire = 36000
282 beaker.cache.long_term.key_length = 256
282 beaker.cache.long_term.key_length = 256
283
283
284 beaker.cache.long_term_file.type = file
284 beaker.cache.long_term_file.type = file
285 beaker.cache.long_term_file.expire = 604800
285 beaker.cache.long_term_file.expire = 604800
286 beaker.cache.long_term_file.key_length = 256
286 beaker.cache.long_term_file.key_length = 256
287
287
288 ####################################
288 ####################################
289 ### BEAKER SESSION ####
289 ### BEAKER SESSION ####
290 ####################################
290 ####################################
291
291
292 ## Name of session cookie. Should be unique for a given host and path, even when running
292 ## Name of session cookie. Should be unique for a given host and path, even when running
293 ## on different ports. Otherwise, cookie sessions will be shared and messed up.
293 ## on different ports. Otherwise, cookie sessions will be shared and messed up.
294 session.key = kallithea
294 session.key = kallithea
295 ## Sessions should always only be accessible by the browser, not directly by JavaScript.
295 ## Sessions should always only be accessible by the browser, not directly by JavaScript.
296 session.httponly = true
296 session.httponly = true
297 ## Session lifetime. 2592000 seconds is 30 days.
297 ## Session lifetime. 2592000 seconds is 30 days.
298 session.timeout = 2592000
298 session.timeout = 2592000
299
299
300 ## Server secret used with HMAC to ensure integrity of cookies.
300 ## Server secret used with HMAC to ensure integrity of cookies.
301 #session.secret = VERY-SECRET
301 #session.secret = VERY-SECRET
302 session.secret = development-not-secret
302 session.secret = development-not-secret
303 ## Further, encrypt the data with AES.
303 ## Further, encrypt the data with AES.
304 #session.encrypt_key = <key_for_encryption>
304 #session.encrypt_key = <key_for_encryption>
305 #session.validate_key = <validation_key>
305 #session.validate_key = <validation_key>
306
306
307 ## Type of storage used for the session, current types are
307 ## Type of storage used for the session, current types are
308 ## dbm, file, memcached, database, and memory.
308 ## dbm, file, memcached, database, and memory.
309
309
310 ## File system storage of session data. (default)
310 ## File system storage of session data. (default)
311 #session.type = file
311 #session.type = file
312
312
313 ## Cookie only, store all session data inside the cookie. Requires secure secrets.
313 ## Cookie only, store all session data inside the cookie. Requires secure secrets.
314 #session.type = cookie
314 #session.type = cookie
315
315
316 ## Database storage of session data.
316 ## Database storage of session data.
317 #session.type = ext:database
317 #session.type = ext:database
318 #session.sa.url = postgresql://postgres:qwe@localhost/kallithea
318 #session.sa.url = postgresql://postgres:qwe@localhost/kallithea
319 #session.table_name = db_session
319 #session.table_name = db_session
320
320
321 ############################
321 ############################
322 ## ERROR HANDLING SYSTEMS ##
322 ## ERROR HANDLING SYSTEMS ##
323 ############################
323 ############################
324
324
325 ## Propagate email settings to ErrorReporter of TurboGears2
325 ## Propagate email settings to ErrorReporter of TurboGears2
326 ## You do not normally need to change these lines
326 ## You do not normally need to change these lines
327 get trace_errors.smtp_server = smtp_server
327 get trace_errors.smtp_server = smtp_server
328 get trace_errors.smtp_port = smtp_port
328 get trace_errors.smtp_port = smtp_port
329 get trace_errors.from_address = error_email_from
329 get trace_errors.from_address = error_email_from
330 get trace_errors.error_email = email_to
330 get trace_errors.error_email = email_to
331 get trace_errors.smtp_username = smtp_username
331 get trace_errors.smtp_username = smtp_username
332 get trace_errors.smtp_password = smtp_password
332 get trace_errors.smtp_password = smtp_password
333 get trace_errors.smtp_use_tls = smtp_use_tls
333 get trace_errors.smtp_use_tls = smtp_use_tls
334
334
335 ################################################################################
335 ################################################################################
336 ## WARNING: *DEBUG MODE MUST BE OFF IN A PRODUCTION ENVIRONMENT* ##
336 ## WARNING: *DEBUG MODE MUST BE OFF IN A PRODUCTION ENVIRONMENT* ##
337 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
337 ## Debug mode will enable the interactive debugging tool, allowing ANYONE to ##
338 ## execute malicious code after an exception is raised. ##
338 ## execute malicious code after an exception is raised. ##
339 ################################################################################
339 ################################################################################
340 #debug = false
340 #debug = false
341 debug = true
341 debug = true
342
342
343 ##################################
343 ##################################
344 ### LOGVIEW CONFIG ###
344 ### LOGVIEW CONFIG ###
345 ##################################
345 ##################################
346
346
347 logview.sqlalchemy = #faa
347 logview.sqlalchemy = #faa
348 logview.pylons.templating = #bfb
348 logview.pylons.templating = #bfb
349 logview.pylons.util = #eee
349 logview.pylons.util = #eee
350
350
351 #########################################################
351 #########################################################
352 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
352 ### DB CONFIGS - EACH DB WILL HAVE IT'S OWN CONFIG ###
353 #########################################################
353 #########################################################
354
354
355 ## SQLITE [default]
355 ## SQLITE [default]
356 sqlalchemy.url = sqlite:///%(here)s/kallithea.db?timeout=60
356 sqlalchemy.url = sqlite:///%(here)s/kallithea.db?timeout=60
357
357
358 ## see sqlalchemy docs for other backends
358 ## see sqlalchemy docs for other backends
359
359
360 sqlalchemy.pool_recycle = 3600
360 sqlalchemy.pool_recycle = 3600
361
361
362 ################################
362 ################################
363 ### ALEMBIC CONFIGURATION ####
363 ### ALEMBIC CONFIGURATION ####
364 ################################
364 ################################
365
365
366 [alembic]
366 [alembic]
367 script_location = kallithea:alembic
367 script_location = kallithea:alembic
368
368
369 ################################
369 ################################
370 ### LOGGING CONFIGURATION ####
370 ### LOGGING CONFIGURATION ####
371 ################################
371 ################################
372
372
373 [loggers]
373 [loggers]
374 keys = root, routes, kallithea, sqlalchemy, tg, gearbox, beaker, templates, whoosh_indexer, werkzeug, backlash
374 keys = root, routes, kallithea, sqlalchemy, tg, gearbox, beaker, templates, whoosh_indexer, werkzeug, backlash
375
375
376 [handlers]
376 [handlers]
377 keys = console, console_color, console_color_sql, null
377 keys = console, console_color, console_color_sql, null
378
378
379 [formatters]
379 [formatters]
380 keys = generic, color_formatter, color_formatter_sql
380 keys = generic, color_formatter, color_formatter_sql
381
381
382 #############
382 #############
383 ## LOGGERS ##
383 ## LOGGERS ##
384 #############
384 #############
385
385
386 [logger_root]
386 [logger_root]
387 level = NOTSET
387 level = NOTSET
388 #handlers = console
388 #handlers = console
389 ## For coloring based on log level:
389 handlers = console_color
390 handlers = console_color
390 ## For coloring based on log level:
391 #handlers = console_color
392
391
393 [logger_routes]
392 [logger_routes]
394 #level = WARN
393 #level = WARN
395 level = DEBUG
394 level = DEBUG
396 handlers =
395 handlers =
397 qualname = routes.middleware
396 qualname = routes.middleware
398 ## "level = DEBUG" logs the route matched and routing variables.
397 ## "level = DEBUG" logs the route matched and routing variables.
399
398
400 [logger_beaker]
399 [logger_beaker]
401 #level = WARN
400 #level = WARN
402 level = DEBUG
401 level = DEBUG
403 handlers =
402 handlers =
404 qualname = beaker.container
403 qualname = beaker.container
405
404
406 [logger_templates]
405 [logger_templates]
407 #level = WARN
406 #level = WARN
408 level = INFO
407 level = INFO
409 handlers =
408 handlers =
410 qualname = pylons.templating
409 qualname = pylons.templating
411
410
412 [logger_kallithea]
411 [logger_kallithea]
413 #level = WARN
412 #level = WARN
414 level = DEBUG
413 level = DEBUG
415 handlers =
414 handlers =
416 qualname = kallithea
415 qualname = kallithea
417
416
418 [logger_tg]
417 [logger_tg]
419 #level = WARN
418 #level = WARN
420 level = DEBUG
419 level = DEBUG
421 handlers =
420 handlers =
422 qualname = tg
421 qualname = tg
423
422
424 [logger_gearbox]
423 [logger_gearbox]
425 #level = WARN
424 #level = WARN
426 level = DEBUG
425 level = DEBUG
427 handlers =
426 handlers =
428 qualname = gearbox
427 qualname = gearbox
429
428
430 [logger_sqlalchemy]
429 [logger_sqlalchemy]
431 level = WARN
430 level = WARN
432 handlers =
431 handlers =
433 qualname = sqlalchemy.engine
432 qualname = sqlalchemy.engine
434 ## For coloring based on log level and pretty printing of SQL:
433 ## For coloring based on log level and pretty printing of SQL:
435 #level = INFO
434 #level = INFO
436 #handlers = console_color_sql
435 #handlers = console_color_sql
437 #propagate = 0
436 #propagate = 0
438
437
439 [logger_whoosh_indexer]
438 [logger_whoosh_indexer]
440 #level = WARN
439 #level = WARN
441 level = DEBUG
440 level = DEBUG
442 handlers =
441 handlers =
443 qualname = whoosh_indexer
442 qualname = whoosh_indexer
444
443
445 [logger_werkzeug]
444 [logger_werkzeug]
446 level = WARN
445 level = WARN
447 handlers =
446 handlers =
448 qualname = werkzeug
447 qualname = werkzeug
449
448
450 [logger_backlash]
449 [logger_backlash]
451 level = WARN
450 level = WARN
452 handlers =
451 handlers =
453 qualname = backlash
452 qualname = backlash
454
453
455 ##############
454 ##############
456 ## HANDLERS ##
455 ## HANDLERS ##
457 ##############
456 ##############
458
457
459 [handler_console]
458 [handler_console]
460 class = StreamHandler
459 class = StreamHandler
461 args = (sys.stderr,)
460 args = (sys.stderr,)
462 formatter = generic
461 formatter = generic
463
462
464 [handler_console_color]
463 [handler_console_color]
465 ## ANSI color coding based on log level
464 ## ANSI color coding based on log level
466 class = StreamHandler
465 class = StreamHandler
467 args = (sys.stderr,)
466 args = (sys.stderr,)
468 formatter = color_formatter
467 formatter = color_formatter
469
468
470 [handler_console_color_sql]
469 [handler_console_color_sql]
471 ## ANSI color coding and pretty printing of SQL statements
470 ## ANSI color coding and pretty printing of SQL statements
472 class = StreamHandler
471 class = StreamHandler
473 args = (sys.stderr,)
472 args = (sys.stderr,)
474 formatter = color_formatter_sql
473 formatter = color_formatter_sql
475
474
476 [handler_null]
475 [handler_null]
477 class = NullHandler
476 class = NullHandler
478 args = ()
477 args = ()
479
478
480 ################
479 ################
481 ## FORMATTERS ##
480 ## FORMATTERS ##
482 ################
481 ################
483
482
484 [formatter_generic]
483 [formatter_generic]
485 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
484 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
486 datefmt = %Y-%m-%d %H:%M:%S
485 datefmt = %Y-%m-%d %H:%M:%S
487
486
488 [formatter_color_formatter]
487 [formatter_color_formatter]
489 class = kallithea.lib.colored_formatter.ColorFormatter
488 class = kallithea.lib.colored_formatter.ColorFormatter
490 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
489 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
491 datefmt = %Y-%m-%d %H:%M:%S
490 datefmt = %Y-%m-%d %H:%M:%S
492
491
493 [formatter_color_formatter_sql]
492 [formatter_color_formatter_sql]
494 class = kallithea.lib.colored_formatter.ColorFormatterSql
493 class = kallithea.lib.colored_formatter.ColorFormatterSql
495 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
494 format = %(asctime)s.%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
496 datefmt = %Y-%m-%d %H:%M:%S
495 datefmt = %Y-%m-%d %H:%M:%S
497
496
498 #################
497 #################
499 ## SSH LOGGING ##
498 ## SSH LOGGING ##
500 #################
499 #################
501
500
502 ## The default loggers use 'handler_console' that uses StreamHandler with
501 ## The default loggers use 'handler_console' that uses StreamHandler with
503 ## destination 'sys.stderr'. In the context of the SSH server process, these log
502 ## destination 'sys.stderr'. In the context of the SSH server process, these log
504 ## messages would be sent to the client, which is normally not what you want.
503 ## messages would be sent to the client, which is normally not what you want.
505 ## By default, when running ssh-serve, just use NullHandler and disable logging
504 ## By default, when running ssh-serve, just use NullHandler and disable logging
506 ## completely. For other logging options, see:
505 ## completely. For other logging options, see:
507 ## https://docs.python.org/2/library/logging.handlers.html
506 ## https://docs.python.org/2/library/logging.handlers.html
508
507
509 [ssh_serve:logger_root]
508 [ssh_serve:logger_root]
510 level = CRITICAL
509 level = CRITICAL
511 handlers = null
510 handlers = null
512
511
513 ## Note: If logging is configured with other handlers, they might need similar
512 ## Note: If logging is configured with other handlers, they might need similar
514 ## muting for ssh-serve too.
513 ## muting for ssh-serve too.
@@ -1,199 +1,220 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 # This program is free software: you can redistribute it and/or modify
2 # This program is free software: you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation, either version 3 of the License, or
4 # the Free Software Foundation, either version 3 of the License, or
5 # (at your option) any later version.
5 # (at your option) any later version.
6 #
6 #
7 # This program is distributed in the hope that it will be useful,
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
10 # GNU General Public License for more details.
11 #
11 #
12 # You should have received a copy of the GNU General Public License
12 # You should have received a copy of the GNU General Public License
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14
14
15 """
15 """
16 kallithea.lib.inifile
16 kallithea.lib.inifile
17 ~~~~~~~~~~~~~~~~~~~~~
17 ~~~~~~~~~~~~~~~~~~~~~
18
18
19 Handling of .ini files, mainly creating them from Mako templates and adding
19 Handling of .ini files, mainly creating them from Mako templates and adding
20 other custom values.
20 other custom values.
21 """
21 """
22
22
23 import logging
23 import logging
24 import os
24 import os
25 import re
25 import re
26
26
27 import mako.template
27 import mako.template
28
28
29
29
30 log = logging.getLogger(__name__)
30 log = logging.getLogger(__name__)
31
31
32
32
33 template_file = os.path.join(
33 template_file = os.path.join(
34 os.path.dirname(os.path.dirname(os.path.dirname(__file__))),
34 os.path.dirname(os.path.dirname(os.path.dirname(__file__))),
35 'kallithea/lib/paster_commands/template.ini.mako')
35 'kallithea/lib/paster_commands/template.ini.mako')
36
36
37 default_variables = {
37 default_variables = {
38 'database_engine': 'sqlite',
38 'database_engine': 'sqlite',
39 'http_server': 'waitress',
39 'http_server': 'waitress',
40 'host': '127.0.0.1',
40 'host': '127.0.0.1',
41 'port': '5000',
41 'port': '5000',
42 'uuid': lambda: 'VERY-SECRET',
42 'uuid': lambda: 'VERY-SECRET',
43 }
43 }
44
44
45 variable_options = {
45 variable_options = {
46 'database_engine': ['sqlite', 'postgres', 'mysql'],
46 'database_engine': ['sqlite', 'postgres', 'mysql'],
47 'http_server': ['waitress', 'gearbox', 'gevent', 'gunicorn', 'uwsgi'],
47 'http_server': ['waitress', 'gearbox', 'gevent', 'gunicorn', 'uwsgi'],
48 }
48 }
49
49
50 def expand(template, mako_variable_values, settings):
50 def expand(template, mako_variable_values, settings):
51 """Expand mako template and tweak it.
51 """Expand mako template and tweak it.
52 Not entirely stable for random templates as input, but good enough for our
52 Not entirely stable for random templates as input, but good enough for our
53 single template.
53 single template.
54
54
55 >>> template = '''
55 >>> template = '''
56 ... [first-section]
56 ... [first-section]
57 ...
57 ...
58 ... variable=${mako_variable}
58 ... variable=${mako_variable}
59 ... variable2 =\tvalue after tab
59 ... variable2 =\tvalue after tab
60 ... ## This section had some whitespace and stuff
60 ... ## This section had some whitespace and stuff
61 ...
61 ...
62 ...
62 ...
63 ... # ${mako_function()}
63 ... # ${mako_function()}
64 ... [second-section]
64 ... [second-section]
65 ... %if conditional_options == 'option-a':
65 ... %if conditional_options == 'option-a':
66 ... # option a was chosen
66 ... # option a was chosen
67 ... %elif conditional_options == 'option-b':
67 ... %elif conditional_options == 'option-b':
68 ... some_variable = "never mind - option-b will not be used anyway ..."
68 ... some_variable = "never mind - option-b will not be used anyway ..."
69 ... %endif
69 ... %endif
70 ...
70 ...
71 ... [comment-section]
71 ... [comment-section]
72 ... #variable3 = 3.0
72 ... #variable3 = 3.0
73 ... #variable4 = 4.0
73 ... #variable4 = 4.0
74 ... #variable5 = 5.0
74 ... #variable5 = 5.0
75 ... variable5 = 5.1
75 ... variable5 = 5.1
76 ... #variable6 = 6.0
76 ... #variable6 = 6.0
77 ... #variable6 = 6.1
77 ... #variable6 = 6.1
78 ... #variable7 = 7.0
78 ... #variable7 = 7.0
79 ... variable7 = 7.1
79 ... variable7 = 7.1
80 ... '''
80 ... '''
81 >>> mako_variable_values = {'mako_variable': 'VALUE', 'mako_function': (lambda: 'FUNCTION RESULT'),
81 >>> mako_variable_values = {'mako_variable': 'VALUE', 'mako_function': (lambda: 'FUNCTION RESULT'),
82 ... 'conditional_options': 'option-a', 'http_server': 'nc'}
82 ... 'conditional_options': 'option-a', 'http_server': 'nc'}
83 >>> settings = { # only partially used
83 >>> settings = { # only partially used
84 ... '[first-section]': {'variable2': 'VAL2', 'first_extra': 'EXTRA'},
84 ... '[first-section]': {'variable2': 'VAL2', 'first_extra': 'EXTRA'},
85 ... '[comment-section]': {'variable3': '3.0', 'variable4': '4.1', 'variable5': '5.2', 'variable6': '6.2', 'variable7': '7.0'},
85 ... '[comment-section]': {'variable3': '3.0', 'variable4': '4.1', 'variable5': '5.2', 'variable6': '6.2', 'variable7': '7.0'},
86 ... '[third-section]': {'third_extra': ' 3'},
86 ... '[third-section]': {'third_extra': ' 3'},
87 ... '[fourth-section]': {'fourth_extra': '4', 'fourth': '"four"'},
87 ... '[fourth-section]': {'fourth_extra': '4', 'fourth': '"four"'},
88 ... }
88 ... }
89 >>> print(expand(template, mako_variable_values, settings))
89 >>> print(expand(template, mako_variable_values, settings))
90 ERROR: http_server is 'nc' - it should be one of 'waitress', 'gearbox', 'gevent', 'gunicorn', 'uwsgi'
90 ERROR: http_server is 'nc' - it should be one of 'waitress', 'gearbox', 'gevent', 'gunicorn', 'uwsgi'
91 <BLANKLINE>
91 <BLANKLINE>
92 [first-section]
92 [first-section]
93 <BLANKLINE>
93 <BLANKLINE>
94 variable=VALUE
94 variable=VALUE
95 #variable2 = value after tab
95 #variable2 = value after tab
96 variable2 = VAL2
96 variable2 = VAL2
97 <BLANKLINE>
97 <BLANKLINE>
98 first_extra = EXTRA
98 first_extra = EXTRA
99 <BLANKLINE>
99 <BLANKLINE>
100 <BLANKLINE>
100 <BLANKLINE>
101 # FUNCTION RESULT
101 # FUNCTION RESULT
102 [second-section]
102 [second-section]
103 # option a was chosen
103 # option a was chosen
104 <BLANKLINE>
104 <BLANKLINE>
105 [comment-section]
105 [comment-section]
106 #variable3 = 3.0
106 variable3 = 3.0
107 #variable4 = 4.0
107 #variable4 = 4.0
108 variable4 = 4.1
108 #variable5 = 5.0
109 #variable5 = 5.0
109 #variable5 = 5.1
110 #variable5 = 5.1
110 variable5 = 5.2
111 variable5 = 5.2
111 #variable6 = 6.0
112 #variable6 = 6.0
112 #variable6 = 6.1
113 #variable6 = 6.1
113 #variable7 = 7.0
114 variable6 = 6.2
114 #variable7 = 7.1
115 variable7 = 7.0
115 variable7 = 7.0
116 <BLANKLINE>
116 #variable7 = 7.1
117 variable3 = 3.0
118 variable4 = 4.1
119 variable6 = 6.2
120 <BLANKLINE>
117 <BLANKLINE>
121 [fourth-section]
118 [fourth-section]
122 fourth = "four"
119 fourth = "four"
123 fourth_extra = 4
120 fourth_extra = 4
124 <BLANKLINE>
121 <BLANKLINE>
125 [third-section]
122 [third-section]
126 third_extra = 3
123 third_extra = 3
127 <BLANKLINE>
124 <BLANKLINE>
128 """
125 """
129 mako_variables = dict(default_variables)
126 mako_variables = dict(default_variables)
130 mako_variables.update(mako_variable_values or {})
127 mako_variables.update(mako_variable_values or {})
131 settings = dict((k, dict(v)) for k, v in settings.items()) # deep copy before mutating
128 settings = dict((k, dict(v)) for k, v in settings.items()) # deep copy before mutating
132
129
133 for key, value in mako_variables.items():
130 for key, value in mako_variables.items():
134 if key in variable_options:
131 if key in variable_options:
135 if value not in variable_options[key]:
132 if value not in variable_options[key]:
136 print('ERROR: %s is %r - it should be one of %s' %
133 print('ERROR: %s is %r - it should be one of %s' %
137 (key, value, ', '.join(repr(x) for x in variable_options[key])))
134 (key, value, ', '.join(repr(x) for x in variable_options[key])))
138
135
139 ini_lines = mako.template.Template(template).render(**mako_variables)
136 ini_lines = mako.template.Template(template).render(**mako_variables)
140
137
141 def process_section(m):
138 def process_section(m):
142 """process a ini section, replacing values as necessary"""
139 """process a ini section, replacing values as necessary"""
143 sectionname, lines = m.groups()
140 sectionname, lines = m.groups()
144 if sectionname in settings:
141 if sectionname in settings:
145 section_settings = settings.pop(sectionname)
142 section_settings = settings.pop(sectionname)
143 add_after_key_value = {} # map key to value it should be added after
146
144
147 def process_line(m):
145 # 1st pass:
148 """process a section line and update value if necessary"""
146 # comment out lines with keys that have new values
149 key, value = m.groups()
147 # find best line for keeping or un-commenting (because it has the right value) or adding after (because it is the last with other value)
148 def comment_out(m):
149 """process a section line if in section_settings and comment out and track in add_after_key_value"""
150 line = m.group(0)
150 line = m.group(0)
151 if key in section_settings:
151 comment, key, line_value = m.groups()
152 new_line = '%s = %s' % (key, section_settings.pop(key))
152 if key not in section_settings:
153 if new_line != line:
153 return line
154 # keep old entry as example - comments might refer to it
154 new_value = section_settings[key]
155 line = '#%s\n%s' % (line, new_line)
155 if line_value == new_value or add_after_key_value.get(key) != new_value:
156 return line.rstrip()
156 add_after_key_value[key] = line_value
157 if comment:
158 return line
159 return '#' + line
160
161 lines = re.sub(r'^(#)?([^#\n\s]*)[ \t]*=[ \t]*(.*)$', comment_out, lines, flags=re.MULTILINE)
157
162
158 # process lines that not are comments or empty and look like name=value
163 def add_after_comment(m):
159 lines = re.sub(r'^([^#\n\s]*)[ \t]*=[ \t]*(.*)$', process_line, lines, flags=re.MULTILINE)
164 """process a section comment line and add new value"""
165 line = m.group(0)
166 key, line_value = m.groups()
167 if key not in section_settings:
168 return line
169 if line_value != add_after_key_value.get(key):
170 return line
171 new_value = section_settings[key]
172 if new_value == line_value:
173 line = line.lstrip('#')
174 else:
175 line += '\n%s = %s' % (key, new_value)
176 section_settings.pop(key)
177 return line
178
179 lines = re.sub(r'^#([^#\n\s]*)[ \t]*=[ \t]*(.*)$', add_after_comment, lines, flags=re.MULTILINE)
180
160 # add unused section settings
181 # add unused section settings
161 if section_settings:
182 if section_settings:
162 lines += '\n' + ''.join('%s = %s\n' % (key, value) for key, value in sorted(section_settings.items()))
183 lines += '\n' + ''.join('%s = %s\n' % (key, value) for key, value in sorted(section_settings.items()))
163
184
164 return sectionname + '\n' + lines
185 return sectionname + '\n' + lines
165
186
166 # process sections until comments before next section or end
187 # process sections until comments before next section or end
167 ini_lines = re.sub(r'''^
188 ini_lines = re.sub(r'''^
168 (\[.*\])\n
189 (\[.*\])\n
169 # after the section name, a number of chunks with:
190 # after the section name, a number of chunks with:
170 (
191 (
171 (?:
192 (?:
172 # a number of comments or empty lines
193 # a number of comments or empty lines
173 (?:[#].*\n|\n)*
194 (?:[#].*\n|\n)*
174 # one or more non-empty non-comments non-section-start lines
195 # one or more non-empty non-comments non-section-start lines
175 (?:[^\n#[].*\n)+
196 (?:[^\n#[].*\n)+
176 # a number of comments - not empty lines
197 # a number of comments - not empty lines
177 (?:[#].*\n)*
198 (?:[#].*\n)*
178 )*
199 )*
179 )
200 )
180 ''',
201 ''',
181 process_section, ini_lines, flags=re.MULTILINE | re.VERBOSE) \
202 process_section, ini_lines, flags=re.MULTILINE | re.VERBOSE) \
182 + \
203 + \
183 ''.join(
204 ''.join(
184 '\n' + sectionname + '\n' + ''.join('%s = %s\n' % (key, value) for key, value in sorted(section_settings.items()))
205 '\n' + sectionname + '\n' + ''.join('%s = %s\n' % (key, value) for key, value in sorted(section_settings.items()))
185 for sectionname, section_settings in sorted(settings.items())
206 for sectionname, section_settings in sorted(settings.items())
186 if section_settings)
207 if section_settings)
187
208
188 return ini_lines
209 return ini_lines
189
210
190
211
191 def create(dest_file, mako_variable_values, settings):
212 def create(dest_file, mako_variable_values, settings):
192 """Create an ini file at dest_file"""
213 """Create an ini file at dest_file"""
193 with open(template_file, 'rb') as f:
214 with open(template_file, 'rb') as f:
194 template = f.read().decode('utf-8')
215 template = f.read().decode('utf-8')
195
216
196 ini_lines = expand(template, mako_variable_values, settings)
217 ini_lines = expand(template, mako_variable_values, settings)
197
218
198 with open(dest_file, 'wb') as f:
219 with open(dest_file, 'wb') as f:
199 f.write(ini_lines.encode('utf-8'))
220 f.write(ini_lines.encode('utf-8'))
General Comments 0
You need to be logged in to leave comments. Login now