We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Specify max resource size in an env variable
### CKAN Version if known (or site URL)
2.7.2 (applies to head of master as well)

### Please describe the expected behaviour
When deploying CKAN through docker it is not ideal to have to edit the configuration file in order to set maximum resource upload size. This would be better done through environment variables.

### Please describe the actual behaviour
Currently the ckan.max_upload_size config can only changed via editing the config .ini files.

### What steps can be taken to reproduce the issue? 
Running CKAN through Docker via Docker Compose.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `ckan/config/environment.py`
Content:
```
1 # encoding: utf-8
2 
3 '''CKAN environment configuration'''
4 import os
5 import logging
6 import warnings
7 from urlparse import urlparse
8 import pytz
9 
10 import sqlalchemy
11 from pylons import config as pylons_config
12 import formencode
13 
14 import ckan.config.routing as routing
15 import ckan.model as model
16 import ckan.plugins as p
17 import ckan.lib.helpers as helpers
18 import ckan.lib.app_globals as app_globals
19 from ckan.lib.redis import is_redis_available
20 import ckan.lib.render as render
21 import ckan.lib.search as search
22 import ckan.logic as logic
23 import ckan.authz as authz
24 import ckan.lib.jinja_extensions as jinja_extensions
25 from ckan.lib.i18n import build_js_translations
26 
27 from ckan.common import _, ungettext, config
28 from ckan.exceptions import CkanConfigurationException
29 
30 log = logging.getLogger(__name__)
31 
32 
33 # Suppress benign warning 'Unbuilt egg for setuptools'
34 warnings.simplefilter('ignore', UserWarning)
35 
36 
37 def load_environment(global_conf, app_conf):
38     """
39     Configure the Pylons environment via the ``pylons.config`` object. This
40     code should only need to be run once.
41     """
42     # this must be run at a time when the env is semi-setup, thus inlined here.
43     # Required by the deliverance plugin and iATI
44     from pylons.wsgiapp import PylonsApp
45     import pkg_resources
46     find_controller_generic = PylonsApp.find_controller
47 
48     # This is from pylons 1.0 source, will monkey-patch into 0.9.7
49     def find_controller(self, controller):
50         if controller in self.controller_classes:
51             return self.controller_classes[controller]
52         # Check to see if its a dotted name
53         if '.' in controller or ':' in controller:
54             ep = pkg_resources.EntryPoint.parse('x={0}'.format(controller))
55 
56             if hasattr(ep, 'resolve'):
57                 # setuptools >= 10.2
58                 mycontroller = ep.resolve()
59             else:
60                 # setuptools >= 11.3
61                 mycontroller = ep.load(False)
62 
63             self.controller_classes[controller] = mycontroller
64             return mycontroller
65         return find_controller_generic(self, controller)
66     PylonsApp.find_controller = find_controller
67 
68     os.environ['CKAN_CONFIG'] = global_conf['__file__']
69 
70     # Pylons paths
71     root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
72 
73     valid_base_public_folder_names = ['public', 'public-bs2']
74     static_files = app_conf.get('ckan.base_public_folder', 'public')
75     app_conf['ckan.base_public_folder'] = static_files
76 
77     if static_files not in valid_base_public_folder_names:
78         raise CkanConfigurationException(
79             'You provided an invalid value for ckan.base_public_folder. '
80             'Possible values are: "public" and "public-bs2".'
81         )
82 
83     log.info('Loading static files from %s' % static_files)
84     paths = dict(root=root,
85                  controllers=os.path.join(root, 'controllers'),
86                  static_files=os.path.join(root, static_files),
87                  templates=[])
88 
89     # Initialize main CKAN config object
90     config.update(global_conf)
91     config.update(app_conf)
92 
93     # Initialize Pylons own config object
94     pylons_config.init_app(global_conf, app_conf, package='ckan', paths=paths)
95 
96     # Update the main CKAN config object with the Pylons specific stuff, as it
97     # quite hard to keep them separated. This should be removed once Pylons
98     # support is dropped
99     config.update(pylons_config)
100 
101     # Setup the SQLAlchemy database engine
102     # Suppress a couple of sqlalchemy warnings
103     msgs = ['^Unicode type received non-unicode bind param value',
104             "^Did not recognize type 'BIGINT' of column 'size'",
105             "^Did not recognize type 'tsvector' of column 'search_vector'"
106             ]
107     for msg in msgs:
108         warnings.filterwarnings('ignore', msg, sqlalchemy.exc.SAWarning)
109 
110     # load all CKAN plugins
111     p.load_all()
112 
113     # Check Redis availability
114     if not is_redis_available():
115         log.critical('Could not connect to Redis.')
116 
117     app_globals.reset()
118 
119     # issue #3260: remove idle transaction
120     # Session that was used for getting all config params nor committed,
121     # neither removed and we have idle connection as result
122     model.Session.commit()
123 
124     # Build JavaScript translations. Must be done after plugins have
125     # been loaded.
126     build_js_translations()
127 
128 
129 # A mapping of config settings that can be overridden by env vars.
130 # Note: Do not remove the following lines, they are used in the docs
131 # Start CONFIG_FROM_ENV_VARS
132 CONFIG_FROM_ENV_VARS = {
133     'sqlalchemy.url': 'CKAN_SQLALCHEMY_URL',
134     'ckan.datastore.write_url': 'CKAN_DATASTORE_WRITE_URL',
135     'ckan.datastore.read_url': 'CKAN_DATASTORE_READ_URL',
136     'ckan.redis.url': 'CKAN_REDIS_URL',
137     'solr_url': 'CKAN_SOLR_URL',
138     'ckan.site_id': 'CKAN_SITE_ID',
139     'ckan.site_url': 'CKAN_SITE_URL',
140     'ckan.storage_path': 'CKAN_STORAGE_PATH',
141     'ckan.datapusher.url': 'CKAN_DATAPUSHER_URL',
142     'smtp.server': 'CKAN_SMTP_SERVER',
143     'smtp.starttls': 'CKAN_SMTP_STARTTLS',
144     'smtp.user': 'CKAN_SMTP_USER',
145     'smtp.password': 'CKAN_SMTP_PASSWORD',
146     'smtp.mail_from': 'CKAN_SMTP_MAIL_FROM'
147 }
148 # End CONFIG_FROM_ENV_VARS
149 
150 
151 def update_config():
152     ''' This code needs to be run when the config is changed to take those
153     changes into account. It is called whenever a plugin is loaded as the
154     plugin might have changed the config values (for instance it might
155     change ckan.site_url) '''
156 
157     for plugin in p.PluginImplementations(p.IConfigurer):
158         # must do update in place as this does not work:
159         # config = plugin.update_config(config)
160         plugin.update_config(config)
161 
162     # Set whitelisted env vars on config object
163     # This is set up before globals are initialized
164 
165     ckan_db = os.environ.get('CKAN_DB', None)
166     if ckan_db:
167         msg = 'Setting CKAN_DB as an env var is deprecated and will be' \
168             ' removed in a future release. Use CKAN_SQLALCHEMY_URL instead.'
169         log.warn(msg)
170         config['sqlalchemy.url'] = ckan_db
171 
172     for option in CONFIG_FROM_ENV_VARS:
173         from_env = os.environ.get(CONFIG_FROM_ENV_VARS[option], None)
174         if from_env:
175             config[option] = from_env
176 
177     root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
178 
179     site_url = config.get('ckan.site_url', '')
180     if not site_url:
181         raise RuntimeError(
182             'ckan.site_url is not configured and it must have a value.'
183             ' Please amend your .ini file.')
184     if not site_url.lower().startswith('http'):
185         raise RuntimeError(
186             'ckan.site_url should be a full URL, including the schema '
187             '(http or https)')
188 
189     display_timezone = config.get('ckan.display_timezone', '')
190     if (display_timezone and
191             display_timezone != 'server' and
192             display_timezone not in pytz.all_timezones):
193         raise CkanConfigurationException(
194             "ckan.display_timezone is not 'server' or a valid timezone"
195         )
196 
197     # Remove backslash from site_url if present
198     config['ckan.site_url'] = config['ckan.site_url'].rstrip('/')
199 
200     ckan_host = config['ckan.host'] = urlparse(site_url).netloc
201     if config.get('ckan.site_id') is None:
202         if ':' in ckan_host:
203             ckan_host, port = ckan_host.split(':')
204         assert ckan_host, 'You need to configure ckan.site_url or ' \
205                           'ckan.site_id for SOLR search-index rebuild to work.'
206         config['ckan.site_id'] = ckan_host
207 
208     # ensure that a favicon has been set
209     favicon = config.get('ckan.favicon', '/base/images/ckan.ico')
210     config['ckan.favicon'] = favicon
211 
212     # Init SOLR settings and check if the schema is compatible
213     # from ckan.lib.search import SolrSettings, check_solr_schema_version
214 
215     # lib.search is imported here as we need the config enabled and parsed
216     search.SolrSettings.init(config.get('solr_url'),
217                              config.get('solr_user'),
218                              config.get('solr_password'))
219     search.check_solr_schema_version()
220 
221     routes_map = routing.make_map()
222     config['routes.map'] = routes_map
223     # The RoutesMiddleware needs its mapper updating if it exists
224     if 'routes.middleware' in config:
225         config['routes.middleware'].mapper = routes_map
226     # routes.named_routes is a CKAN thing
227     config['routes.named_routes'] = routing.named_routes
228     config['pylons.app_globals'] = app_globals.app_globals
229     # initialise the globals
230     app_globals.app_globals._init()
231 
232     helpers.load_plugin_helpers()
233     config['pylons.h'] = helpers.helper_functions
234 
235     # Templates and CSS loading from configuration
236     valid_base_templates_folder_names = ['templates', 'templates-bs2']
237     templates = config.get('ckan.base_templates_folder', 'templates')
238     config['ckan.base_templates_folder'] = templates
239 
240     if templates not in valid_base_templates_folder_names:
241         raise CkanConfigurationException(
242             'You provided an invalid value for ckan.base_templates_folder. '
243             'Possible values are: "templates" and "templates-bs2".'
244         )
245 
246     jinja2_templates_path = os.path.join(root, templates)
247     log.info('Loading templates from %s' % jinja2_templates_path)
248     template_paths = [jinja2_templates_path]
249 
250     extra_template_paths = config.get('extra_template_paths', '')
251     if extra_template_paths:
252         # must be first for them to override defaults
253         template_paths = extra_template_paths.split(',') + template_paths
254     config['computed_template_paths'] = template_paths
255 
256     # Set the default language for validation messages from formencode
257     # to what is set as the default locale in the config
258     default_lang = config.get('ckan.locale_default', 'en')
259     formencode.api.set_stdtranslation(domain="FormEncode",
260                                       languages=[default_lang])
261 
262     # Markdown ignores the logger config, so to get rid of excessive
263     # markdown debug messages in the log, set it to the level of the
264     # root logger.
265     logging.getLogger("MARKDOWN").setLevel(logging.getLogger().level)
266 
267     # Create Jinja2 environment
268     env = jinja_extensions.Environment(
269         **jinja_extensions.get_jinja_env_options())
270     env.install_gettext_callables(_, ungettext, newstyle=True)
271     # custom filters
272     env.filters['empty_and_escape'] = jinja_extensions.empty_and_escape
273     config['pylons.app_globals'].jinja_env = env
274 
275     # CONFIGURATION OPTIONS HERE (note: all config options will override
276     # any Pylons config options)
277 
278     # Initialize SQLAlchemy
279     engine = sqlalchemy.engine_from_config(config, client_encoding='utf8')
280     model.init_model(engine)
281 
282     for plugin in p.PluginImplementations(p.IConfigurable):
283         plugin.configure(config)
284 
285     # reset the template cache - we do this here so that when we load the
286     # environment it is clean
287     render.reset_template_info_cache()
288 
289     # clear other caches
290     logic.clear_actions_cache()
291     logic.clear_validators_cache()
292     authz.clear_auth_functions_cache()
293 
294     # Here we create the site user if they are not already in the database
295     try:
296         logic.get_action('get_site_user')({'ignore_auth': True}, None)
297     except (sqlalchemy.exc.ProgrammingError, sqlalchemy.exc.OperationalError):
298         # (ProgrammingError for Postgres, OperationalError for SQLite)
299         # The database is not initialised.  This is a bit dirty.  This occurs
300         # when running tests.
301         pass
302     except sqlalchemy.exc.InternalError:
303         # The database is not initialised.  Travis hits this
304         pass
305 
306     # Close current session and open database connections to ensure a clean
307     # clean environment even if an error occurs later on
308     model.Session.remove()
309     model.Session.bind.dispose()
310
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/ckan/config/environment.py b/ckan/config/environment.py
--- a/ckan/config/environment.py
+++ b/ckan/config/environment.py
@@ -143,7 +143,8 @@
     'smtp.starttls': 'CKAN_SMTP_STARTTLS',
     'smtp.user': 'CKAN_SMTP_USER',
     'smtp.password': 'CKAN_SMTP_PASSWORD',
-    'smtp.mail_from': 'CKAN_SMTP_MAIL_FROM'
+    'smtp.mail_from': 'CKAN_SMTP_MAIL_FROM',
+    'ckan.max_resource_size': 'CKAN_MAX_UPLOAD_SIZE_MB'
 }
 # End CONFIG_FROM_ENV_VARS

{"golden_diff": "diff --git a/ckan/config/environment.py b/ckan/config/environment.py\n--- a/ckan/config/environment.py\n+++ b/ckan/config/environment.py\n@@ -143,7 +143,8 @@\n     'smtp.starttls': 'CKAN_SMTP_STARTTLS',\n     'smtp.user': 'CKAN_SMTP_USER',\n     'smtp.password': 'CKAN_SMTP_PASSWORD',\n-    'smtp.mail_from': 'CKAN_SMTP_MAIL_FROM'\n+    'smtp.mail_from': 'CKAN_SMTP_MAIL_FROM',\n+    'ckan.max_resource_size': 'CKAN_MAX_UPLOAD_SIZE_MB'\n }\n # End CONFIG_FROM_ENV_VARS\n", "issue": "Specify max resource size in an env variable\n### CKAN Version if known (or site URL)\r\n2.7.2 (applies to head of master as well)\r\n\r\n### Please describe the expected behaviour\r\nWhen deploying CKAN through docker it is not ideal to have to edit the configuration file in order to set maximum resource upload size. This would be better done through environment variables.\r\n\r\n### Please describe the actual behaviour\r\nCurrently the ckan.max_upload_size config can only changed via editing the config .ini files.\r\n\r\n### What steps can be taken to reproduce the issue? \r\nRunning CKAN through Docker via Docker Compose.\n", "before_files": [{"content": "# encoding: utf-8\n\n'''CKAN environment configuration'''\nimport os\nimport logging\nimport warnings\nfrom urlparse import urlparse\nimport pytz\n\nimport sqlalchemy\nfrom pylons import config as pylons_config\nimport formencode\n\nimport ckan.config.routing as routing\nimport ckan.model as model\nimport ckan.plugins as p\nimport ckan.lib.helpers as helpers\nimport ckan.lib.app_globals as app_globals\nfrom ckan.lib.redis import is_redis_available\nimport ckan.lib.render as render\nimport ckan.lib.search as search\nimport ckan.logic as logic\nimport ckan.authz as authz\nimport ckan.lib.jinja_extensions as jinja_extensions\nfrom ckan.lib.i18n import build_js_translations\n\nfrom ckan.common import _, ungettext, config\nfrom ckan.exceptions import CkanConfigurationException\n\nlog = logging.getLogger(__name__)\n\n\n# Suppress benign warning 'Unbuilt egg for setuptools'\nwarnings.simplefilter('ignore', UserWarning)\n\n\ndef load_environment(global_conf, app_conf):\n    \"\"\"\n    Configure the Pylons environment via the ``pylons.config`` object. This\n    code should only need to be run once.\n    \"\"\"\n    # this must be run at a time when the env is semi-setup, thus inlined here.\n    # Required by the deliverance plugin and iATI\n    from pylons.wsgiapp import PylonsApp\n    import pkg_resources\n    find_controller_generic = PylonsApp.find_controller\n\n    # This is from pylons 1.0 source, will monkey-patch into 0.9.7\n    def find_controller(self, controller):\n        if controller in self.controller_classes:\n            return self.controller_classes[controller]\n        # Check to see if its a dotted name\n        if '.' in controller or ':' in controller:\n            ep = pkg_resources.EntryPoint.parse('x={0}'.format(controller))\n\n            if hasattr(ep, 'resolve'):\n                # setuptools >= 10.2\n                mycontroller = ep.resolve()\n            else:\n                # setuptools >= 11.3\n                mycontroller = ep.load(False)\n\n            self.controller_classes[controller] = mycontroller\n            return mycontroller\n        return find_controller_generic(self, controller)\n    PylonsApp.find_controller = find_controller\n\n    os.environ['CKAN_CONFIG'] = global_conf['__file__']\n\n    # Pylons paths\n    root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\n\n    valid_base_public_folder_names = ['public', 'public-bs2']\n    static_files = app_conf.get('ckan.base_public_folder', 'public')\n    app_conf['ckan.base_public_folder'] = static_files\n\n    if static_files not in valid_base_public_folder_names:\n        raise CkanConfigurationException(\n            'You provided an invalid value for ckan.base_public_folder. '\n            'Possible values are: \"public\" and \"public-bs2\".'\n        )\n\n    log.info('Loading static files from %s' % static_files)\n    paths = dict(root=root,\n                 controllers=os.path.join(root, 'controllers'),\n                 static_files=os.path.join(root, static_files),\n                 templates=[])\n\n    # Initialize main CKAN config object\n    config.update(global_conf)\n    config.update(app_conf)\n\n    # Initialize Pylons own config object\n    pylons_config.init_app(global_conf, app_conf, package='ckan', paths=paths)\n\n    # Update the main CKAN config object with the Pylons specific stuff, as it\n    # quite hard to keep them separated. This should be removed once Pylons\n    # support is dropped\n    config.update(pylons_config)\n\n    # Setup the SQLAlchemy database engine\n    # Suppress a couple of sqlalchemy warnings\n    msgs = ['^Unicode type received non-unicode bind param value',\n            \"^Did not recognize type 'BIGINT' of column 'size'\",\n            \"^Did not recognize type 'tsvector' of column 'search_vector'\"\n            ]\n    for msg in msgs:\n        warnings.filterwarnings('ignore', msg, sqlalchemy.exc.SAWarning)\n\n    # load all CKAN plugins\n    p.load_all()\n\n    # Check Redis availability\n    if not is_redis_available():\n        log.critical('Could not connect to Redis.')\n\n    app_globals.reset()\n\n    # issue #3260: remove idle transaction\n    # Session that was used for getting all config params nor committed,\n    # neither removed and we have idle connection as result\n    model.Session.commit()\n\n    # Build JavaScript translations. Must be done after plugins have\n    # been loaded.\n    build_js_translations()\n\n\n# A mapping of config settings that can be overridden by env vars.\n# Note: Do not remove the following lines, they are used in the docs\n# Start CONFIG_FROM_ENV_VARS\nCONFIG_FROM_ENV_VARS = {\n    'sqlalchemy.url': 'CKAN_SQLALCHEMY_URL',\n    'ckan.datastore.write_url': 'CKAN_DATASTORE_WRITE_URL',\n    'ckan.datastore.read_url': 'CKAN_DATASTORE_READ_URL',\n    'ckan.redis.url': 'CKAN_REDIS_URL',\n    'solr_url': 'CKAN_SOLR_URL',\n    'ckan.site_id': 'CKAN_SITE_ID',\n    'ckan.site_url': 'CKAN_SITE_URL',\n    'ckan.storage_path': 'CKAN_STORAGE_PATH',\n    'ckan.datapusher.url': 'CKAN_DATAPUSHER_URL',\n    'smtp.server': 'CKAN_SMTP_SERVER',\n    'smtp.starttls': 'CKAN_SMTP_STARTTLS',\n    'smtp.user': 'CKAN_SMTP_USER',\n    'smtp.password': 'CKAN_SMTP_PASSWORD',\n    'smtp.mail_from': 'CKAN_SMTP_MAIL_FROM'\n}\n# End CONFIG_FROM_ENV_VARS\n\n\ndef update_config():\n    ''' This code needs to be run when the config is changed to take those\n    changes into account. It is called whenever a plugin is loaded as the\n    plugin might have changed the config values (for instance it might\n    change ckan.site_url) '''\n\n    for plugin in p.PluginImplementations(p.IConfigurer):\n        # must do update in place as this does not work:\n        # config = plugin.update_config(config)\n        plugin.update_config(config)\n\n    # Set whitelisted env vars on config object\n    # This is set up before globals are initialized\n\n    ckan_db = os.environ.get('CKAN_DB', None)\n    if ckan_db:\n        msg = 'Setting CKAN_DB as an env var is deprecated and will be' \\\n            ' removed in a future release. Use CKAN_SQLALCHEMY_URL instead.'\n        log.warn(msg)\n        config['sqlalchemy.url'] = ckan_db\n\n    for option in CONFIG_FROM_ENV_VARS:\n        from_env = os.environ.get(CONFIG_FROM_ENV_VARS[option], None)\n        if from_env:\n            config[option] = from_env\n\n    root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\n\n    site_url = config.get('ckan.site_url', '')\n    if not site_url:\n        raise RuntimeError(\n            'ckan.site_url is not configured and it must have a value.'\n            ' Please amend your .ini file.')\n    if not site_url.lower().startswith('http'):\n        raise RuntimeError(\n            'ckan.site_url should be a full URL, including the schema '\n            '(http or https)')\n\n    display_timezone = config.get('ckan.display_timezone', '')\n    if (display_timezone and\n            display_timezone != 'server' and\n            display_timezone not in pytz.all_timezones):\n        raise CkanConfigurationException(\n            \"ckan.display_timezone is not 'server' or a valid timezone\"\n        )\n\n    # Remove backslash from site_url if present\n    config['ckan.site_url'] = config['ckan.site_url'].rstrip('/')\n\n    ckan_host = config['ckan.host'] = urlparse(site_url).netloc\n    if config.get('ckan.site_id') is None:\n        if ':' in ckan_host:\n            ckan_host, port = ckan_host.split(':')\n        assert ckan_host, 'You need to configure ckan.site_url or ' \\\n                          'ckan.site_id for SOLR search-index rebuild to work.'\n        config['ckan.site_id'] = ckan_host\n\n    # ensure that a favicon has been set\n    favicon = config.get('ckan.favicon', '/base/images/ckan.ico')\n    config['ckan.favicon'] = favicon\n\n    # Init SOLR settings and check if the schema is compatible\n    # from ckan.lib.search import SolrSettings, check_solr_schema_version\n\n    # lib.search is imported here as we need the config enabled and parsed\n    search.SolrSettings.init(config.get('solr_url'),\n                             config.get('solr_user'),\n                             config.get('solr_password'))\n    search.check_solr_schema_version()\n\n    routes_map = routing.make_map()\n    config['routes.map'] = routes_map\n    # The RoutesMiddleware needs its mapper updating if it exists\n    if 'routes.middleware' in config:\n        config['routes.middleware'].mapper = routes_map\n    # routes.named_routes is a CKAN thing\n    config['routes.named_routes'] = routing.named_routes\n    config['pylons.app_globals'] = app_globals.app_globals\n    # initialise the globals\n    app_globals.app_globals._init()\n\n    helpers.load_plugin_helpers()\n    config['pylons.h'] = helpers.helper_functions\n\n    # Templates and CSS loading from configuration\n    valid_base_templates_folder_names = ['templates', 'templates-bs2']\n    templates = config.get('ckan.base_templates_folder', 'templates')\n    config['ckan.base_templates_folder'] = templates\n\n    if templates not in valid_base_templates_folder_names:\n        raise CkanConfigurationException(\n            'You provided an invalid value for ckan.base_templates_folder. '\n            'Possible values are: \"templates\" and \"templates-bs2\".'\n        )\n\n    jinja2_templates_path = os.path.join(root, templates)\n    log.info('Loading templates from %s' % jinja2_templates_path)\n    template_paths = [jinja2_templates_path]\n\n    extra_template_paths = config.get('extra_template_paths', '')\n    if extra_template_paths:\n        # must be first for them to override defaults\n        template_paths = extra_template_paths.split(',') + template_paths\n    config['computed_template_paths'] = template_paths\n\n    # Set the default language for validation messages from formencode\n    # to what is set as the default locale in the config\n    default_lang = config.get('ckan.locale_default', 'en')\n    formencode.api.set_stdtranslation(domain=\"FormEncode\",\n                                      languages=[default_lang])\n\n    # Markdown ignores the logger config, so to get rid of excessive\n    # markdown debug messages in the log, set it to the level of the\n    # root logger.\n    logging.getLogger(\"MARKDOWN\").setLevel(logging.getLogger().level)\n\n    # Create Jinja2 environment\n    env = jinja_extensions.Environment(\n        **jinja_extensions.get_jinja_env_options())\n    env.install_gettext_callables(_, ungettext, newstyle=True)\n    # custom filters\n    env.filters['empty_and_escape'] = jinja_extensions.empty_and_escape\n    config['pylons.app_globals'].jinja_env = env\n\n    # CONFIGURATION OPTIONS HERE (note: all config options will override\n    # any Pylons config options)\n\n    # Initialize SQLAlchemy\n    engine = sqlalchemy.engine_from_config(config, client_encoding='utf8')\n    model.init_model(engine)\n\n    for plugin in p.PluginImplementations(p.IConfigurable):\n        plugin.configure(config)\n\n    # reset the template cache - we do this here so that when we load the\n    # environment it is clean\n    render.reset_template_info_cache()\n\n    # clear other caches\n    logic.clear_actions_cache()\n    logic.clear_validators_cache()\n    authz.clear_auth_functions_cache()\n\n    # Here we create the site user if they are not already in the database\n    try:\n        logic.get_action('get_site_user')({'ignore_auth': True}, None)\n    except (sqlalchemy.exc.ProgrammingError, sqlalchemy.exc.OperationalError):\n        # (ProgrammingError for Postgres, OperationalError for SQLite)\n        # The database is not initialised.  This is a bit dirty.  This occurs\n        # when running tests.\n        pass\n    except sqlalchemy.exc.InternalError:\n        # The database is not initialised.  Travis hits this\n        pass\n\n    # Close current session and open database connections to ensure a clean\n    # clean environment even if an error occurs later on\n    model.Session.remove()\n    model.Session.bind.dispose()\n", "path": "ckan/config/environment.py"}], "after_files": [{"content": "# encoding: utf-8\n\n'''CKAN environment configuration'''\nimport os\nimport logging\nimport warnings\nfrom urlparse import urlparse\nimport pytz\n\nimport sqlalchemy\nfrom pylons import config as pylons_config\nimport formencode\n\nimport ckan.config.routing as routing\nimport ckan.model as model\nimport ckan.plugins as p\nimport ckan.lib.helpers as helpers\nimport ckan.lib.app_globals as app_globals\nfrom ckan.lib.redis import is_redis_available\nimport ckan.lib.render as render\nimport ckan.lib.search as search\nimport ckan.logic as logic\nimport ckan.authz as authz\nimport ckan.lib.jinja_extensions as jinja_extensions\nfrom ckan.lib.i18n import build_js_translations\n\nfrom ckan.common import _, ungettext, config\nfrom ckan.exceptions import CkanConfigurationException\n\nlog = logging.getLogger(__name__)\n\n\n# Suppress benign warning 'Unbuilt egg for setuptools'\nwarnings.simplefilter('ignore', UserWarning)\n\n\ndef load_environment(global_conf, app_conf):\n    \"\"\"\n    Configure the Pylons environment via the ``pylons.config`` object. This\n    code should only need to be run once.\n    \"\"\"\n    # this must be run at a time when the env is semi-setup, thus inlined here.\n    # Required by the deliverance plugin and iATI\n    from pylons.wsgiapp import PylonsApp\n    import pkg_resources\n    find_controller_generic = PylonsApp.find_controller\n\n    # This is from pylons 1.0 source, will monkey-patch into 0.9.7\n    def find_controller(self, controller):\n        if controller in self.controller_classes:\n            return self.controller_classes[controller]\n        # Check to see if its a dotted name\n        if '.' in controller or ':' in controller:\n            ep = pkg_resources.EntryPoint.parse('x={0}'.format(controller))\n\n            if hasattr(ep, 'resolve'):\n                # setuptools >= 10.2\n                mycontroller = ep.resolve()\n            else:\n                # setuptools >= 11.3\n                mycontroller = ep.load(False)\n\n            self.controller_classes[controller] = mycontroller\n            return mycontroller\n        return find_controller_generic(self, controller)\n    PylonsApp.find_controller = find_controller\n\n    os.environ['CKAN_CONFIG'] = global_conf['__file__']\n\n    # Pylons paths\n    root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\n\n    valid_base_public_folder_names = ['public', 'public-bs2']\n    static_files = app_conf.get('ckan.base_public_folder', 'public')\n    app_conf['ckan.base_public_folder'] = static_files\n\n    if static_files not in valid_base_public_folder_names:\n        raise CkanConfigurationException(\n            'You provided an invalid value for ckan.base_public_folder. '\n            'Possible values are: \"public\" and \"public-bs2\".'\n        )\n\n    log.info('Loading static files from %s' % static_files)\n    paths = dict(root=root,\n                 controllers=os.path.join(root, 'controllers'),\n                 static_files=os.path.join(root, static_files),\n                 templates=[])\n\n    # Initialize main CKAN config object\n    config.update(global_conf)\n    config.update(app_conf)\n\n    # Initialize Pylons own config object\n    pylons_config.init_app(global_conf, app_conf, package='ckan', paths=paths)\n\n    # Update the main CKAN config object with the Pylons specific stuff, as it\n    # quite hard to keep them separated. This should be removed once Pylons\n    # support is dropped\n    config.update(pylons_config)\n\n    # Setup the SQLAlchemy database engine\n    # Suppress a couple of sqlalchemy warnings\n    msgs = ['^Unicode type received non-unicode bind param value',\n            \"^Did not recognize type 'BIGINT' of column 'size'\",\n            \"^Did not recognize type 'tsvector' of column 'search_vector'\"\n            ]\n    for msg in msgs:\n        warnings.filterwarnings('ignore', msg, sqlalchemy.exc.SAWarning)\n\n    # load all CKAN plugins\n    p.load_all()\n\n    # Check Redis availability\n    if not is_redis_available():\n        log.critical('Could not connect to Redis.')\n\n    app_globals.reset()\n\n    # issue #3260: remove idle transaction\n    # Session that was used for getting all config params nor committed,\n    # neither removed and we have idle connection as result\n    model.Session.commit()\n\n    # Build JavaScript translations. Must be done after plugins have\n    # been loaded.\n    build_js_translations()\n\n\n# A mapping of config settings that can be overridden by env vars.\n# Note: Do not remove the following lines, they are used in the docs\n# Start CONFIG_FROM_ENV_VARS\nCONFIG_FROM_ENV_VARS = {\n    'sqlalchemy.url': 'CKAN_SQLALCHEMY_URL',\n    'ckan.datastore.write_url': 'CKAN_DATASTORE_WRITE_URL',\n    'ckan.datastore.read_url': 'CKAN_DATASTORE_READ_URL',\n    'ckan.redis.url': 'CKAN_REDIS_URL',\n    'solr_url': 'CKAN_SOLR_URL',\n    'ckan.site_id': 'CKAN_SITE_ID',\n    'ckan.site_url': 'CKAN_SITE_URL',\n    'ckan.storage_path': 'CKAN_STORAGE_PATH',\n    'ckan.datapusher.url': 'CKAN_DATAPUSHER_URL',\n    'smtp.server': 'CKAN_SMTP_SERVER',\n    'smtp.starttls': 'CKAN_SMTP_STARTTLS',\n    'smtp.user': 'CKAN_SMTP_USER',\n    'smtp.password': 'CKAN_SMTP_PASSWORD',\n    'smtp.mail_from': 'CKAN_SMTP_MAIL_FROM',\n    'ckan.max_resource_size': 'CKAN_MAX_UPLOAD_SIZE_MB'\n}\n# End CONFIG_FROM_ENV_VARS\n\n\ndef update_config():\n    ''' This code needs to be run when the config is changed to take those\n    changes into account. It is called whenever a plugin is loaded as the\n    plugin might have changed the config values (for instance it might\n    change ckan.site_url) '''\n\n    for plugin in p.PluginImplementations(p.IConfigurer):\n        # must do update in place as this does not work:\n        # config = plugin.update_config(config)\n        plugin.update_config(config)\n\n    # Set whitelisted env vars on config object\n    # This is set up before globals are initialized\n\n    ckan_db = os.environ.get('CKAN_DB', None)\n    if ckan_db:\n        msg = 'Setting CKAN_DB as an env var is deprecated and will be' \\\n            ' removed in a future release. Use CKAN_SQLALCHEMY_URL instead.'\n        log.warn(msg)\n        config['sqlalchemy.url'] = ckan_db\n\n    for option in CONFIG_FROM_ENV_VARS:\n        from_env = os.environ.get(CONFIG_FROM_ENV_VARS[option], None)\n        if from_env:\n            config[option] = from_env\n\n    root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))\n\n    site_url = config.get('ckan.site_url', '')\n    if not site_url:\n        raise RuntimeError(\n            'ckan.site_url is not configured and it must have a value.'\n            ' Please amend your .ini file.')\n    if not site_url.lower().startswith('http'):\n        raise RuntimeError(\n            'ckan.site_url should be a full URL, including the schema '\n            '(http or https)')\n\n    display_timezone = config.get('ckan.display_timezone', '')\n    if (display_timezone and\n            display_timezone != 'server' and\n            display_timezone not in pytz.all_timezones):\n        raise CkanConfigurationException(\n            \"ckan.display_timezone is not 'server' or a valid timezone\"\n        )\n\n    # Remove backslash from site_url if present\n    config['ckan.site_url'] = config['ckan.site_url'].rstrip('/')\n\n    ckan_host = config['ckan.host'] = urlparse(site_url).netloc\n    if config.get('ckan.site_id') is None:\n        if ':' in ckan_host:\n            ckan_host, port = ckan_host.split(':')\n        assert ckan_host, 'You need to configure ckan.site_url or ' \\\n                          'ckan.site_id for SOLR search-index rebuild to work.'\n        config['ckan.site_id'] = ckan_host\n\n    # ensure that a favicon has been set\n    favicon = config.get('ckan.favicon', '/base/images/ckan.ico')\n    config['ckan.favicon'] = favicon\n\n    # Init SOLR settings and check if the schema is compatible\n    # from ckan.lib.search import SolrSettings, check_solr_schema_version\n\n    # lib.search is imported here as we need the config enabled and parsed\n    search.SolrSettings.init(config.get('solr_url'),\n                             config.get('solr_user'),\n                             config.get('solr_password'))\n    search.check_solr_schema_version()\n\n    routes_map = routing.make_map()\n    config['routes.map'] = routes_map\n    # The RoutesMiddleware needs its mapper updating if it exists\n    if 'routes.middleware' in config:\n        config['routes.middleware'].mapper = routes_map\n    # routes.named_routes is a CKAN thing\n    config['routes.named_routes'] = routing.named_routes\n    config['pylons.app_globals'] = app_globals.app_globals\n    # initialise the globals\n    app_globals.app_globals._init()\n\n    helpers.load_plugin_helpers()\n    config['pylons.h'] = helpers.helper_functions\n\n    # Templates and CSS loading from configuration\n    valid_base_templates_folder_names = ['templates', 'templates-bs2']\n    templates = config.get('ckan.base_templates_folder', 'templates')\n    config['ckan.base_templates_folder'] = templates\n\n    if templates not in valid_base_templates_folder_names:\n        raise CkanConfigurationException(\n            'You provided an invalid value for ckan.base_templates_folder. '\n            'Possible values are: \"templates\" and \"templates-bs2\".'\n        )\n\n    jinja2_templates_path = os.path.join(root, templates)\n    log.info('Loading templates from %s' % jinja2_templates_path)\n    template_paths = [jinja2_templates_path]\n\n    extra_template_paths = config.get('extra_template_paths', '')\n    if extra_template_paths:\n        # must be first for them to override defaults\n        template_paths = extra_template_paths.split(',') + template_paths\n    config['computed_template_paths'] = template_paths\n\n    # Set the default language for validation messages from formencode\n    # to what is set as the default locale in the config\n    default_lang = config.get('ckan.locale_default', 'en')\n    formencode.api.set_stdtranslation(domain=\"FormEncode\",\n                                      languages=[default_lang])\n\n    # Markdown ignores the logger config, so to get rid of excessive\n    # markdown debug messages in the log, set it to the level of the\n    # root logger.\n    logging.getLogger(\"MARKDOWN\").setLevel(logging.getLogger().level)\n\n    # Create Jinja2 environment\n    env = jinja_extensions.Environment(\n        loader=jinja_extensions.CkanFileSystemLoader(template_paths),\n        autoescape=True,\n        extensions=['jinja2.ext.do', 'jinja2.ext.with_',\n                    jinja_extensions.SnippetExtension,\n                    jinja_extensions.CkanExtend,\n                    jinja_extensions.CkanInternationalizationExtension,\n                    jinja_extensions.LinkForExtension,\n                    jinja_extensions.ResourceExtension,\n                    jinja_extensions.UrlForStaticExtension,\n                    jinja_extensions.UrlForExtension]\n    )\n    env.install_gettext_callables(_, ungettext, newstyle=True)\n    # custom filters\n    env.filters['empty_and_escape'] = jinja_extensions.empty_and_escape\n    config['pylons.app_globals'].jinja_env = env\n\n    # CONFIGURATION OPTIONS HERE (note: all config options will override\n    # any Pylons config options)\n\n    # Initialize SQLAlchemy\n    engine = sqlalchemy.engine_from_config(config, client_encoding='utf8')\n    model.init_model(engine)\n\n    for plugin in p.PluginImplementations(p.IConfigurable):\n        plugin.configure(config)\n\n    # reset the template cache - we do this here so that when we load the\n    # environment it is clean\n    render.reset_template_info_cache()\n\n    # clear other caches\n    logic.clear_actions_cache()\n    logic.clear_validators_cache()\n    authz.clear_auth_functions_cache()\n\n    # Here we create the site user if they are not already in the database\n    try:\n        logic.get_action('get_site_user')({'ignore_auth': True}, None)\n    except (sqlalchemy.exc.ProgrammingError, sqlalchemy.exc.OperationalError):\n        # (ProgrammingError for Postgres, OperationalError for SQLite)\n        # The database is not initialised.  This is a bit dirty.  This occurs\n        # when running tests.\n        pass\n    except sqlalchemy.exc.InternalError:\n        # The database is not initialised.  Travis hits this\n        pass\n\n    # Close current session and open database connections to ensure a clean\n    # clean environment even if an error occurs later on\n    model.Session.remove()\n    model.Session.bind.dispose()\n", "path": "ckan/config/environment.py"}]}