diff --git a/changes/8219.feature b/changes/8219.feature new file mode 100644 index 00000000000..544268dfa5d --- /dev/null +++ b/changes/8219.feature @@ -0,0 +1,2 @@ +- Improved start-up performance +- JS translations are no longer generated on each server restart. The are built when starting the development server with `ckan run` or explicitly with `ckan translations js` diff --git a/ckan/cli/cli.py b/ckan/cli/cli.py index 9835c3b692b..0f3a56e5a56 100644 --- a/ckan/cli/cli.py +++ b/ckan/cli/cli.py @@ -76,7 +76,8 @@ def format_commands( # provided, except for `--help`. In this case it has to be done # manually. if not ctx.obj: - _add_ctx_object(ctx) + if '-h' not in sys.argv[1:] and '--help' not in sys.argv[1:]: + _add_ctx_object(ctx) _add_external_commands(ctx) commands = [] @@ -127,7 +128,8 @@ def parse_args(self, ctx: click.Context, args: list[str]): def _init_ckan_config(ctx: click.Context, param: str, value: str): if any(sys.argv[1:len(cmd) + 1] == cmd for cmd in _no_config_commands): return - _add_ctx_object(ctx, value) + if '-h' not in sys.argv[1:] and '--help' not in sys.argv[1:]: + _add_ctx_object(ctx, value) _add_external_commands(ctx) diff --git a/ckan/cli/server.py b/ckan/cli/server.py index 190c72ea1c4..425a184f3a1 100644 --- a/ckan/cli/server.py +++ b/ckan/cli/server.py @@ -12,6 +12,7 @@ from ckan.common import config from . import error_shout +from ckan.lib.i18n import build_js_translations log = logging.getLogger(__name__) @@ -59,7 +60,7 @@ def run(ctx: click.Context, host: str, port: str, disable_reloader: bool, passthrough_errors: bool, disable_debugger: bool, threaded: bool, extra_files: list[str], processes: int, ssl_cert: Optional[str], ssl_key: Optional[str], prefix: Optional[str]): - u"""Runs the Werkzeug development server""" + """Regenerate JS translations and run the Werkzeug development server""" if config.get("debug"): warnings.filterwarnings("default", category=CkanDeprecationWarning) @@ -115,6 +116,9 @@ def run(ctx: click.Context, host: str, port: str, disable_reloader: bool, error_shout(u"Server port must be an integer, not {}".format(port)) raise click.Abort() + # Once automatic on startup, run only here for faster debug iterations + build_js_translations() + log.info(u"Running CKAN on {scheme}://{host}:{port}{prefix}".format( scheme='https' if ssl_context else 'http', host=host, port=port_int, prefix=prefix)) diff --git a/ckan/config/declaration/load.py b/ckan/config/declaration/load.py index a998f5fab46..e52fb16dea7 100644 --- a/ckan/config/declaration/load.py +++ b/ckan/config/declaration/load.py @@ -25,7 +25,7 @@ def load_from_custom(declaration, *args, **kwargs): import pathlib from typing import TYPE_CHECKING, Any, Callable, Dict, List from typing_extensions import TypedDict -import yaml +import msgspec from .key import Key from .option import Flag, Option @@ -156,6 +156,6 @@ def load_core(declaration: "Declaration"): """Load core declarations. """ source = pathlib.Path(__file__).parent / ".." / "config_declaration.yaml" - with source.open("r") as stream: - data = yaml.safe_load(stream) + with source.open("rb") as stream: + data = msgspec.yaml.decode(stream.read()) load_dict(declaration, data) diff --git a/ckan/config/environment.py b/ckan/config/environment.py index 26b51edae2e..9de9e7cf09e 100644 --- a/ckan/config/environment.py +++ b/ckan/config/environment.py @@ -22,7 +22,6 @@ import ckan.logic as logic import ckan.authz as authz from ckan.lib.webassets_tools import webassets_init, register_core_assets -from ckan.lib.i18n import build_js_translations from ckan.common import CKANConfig, config, config_declaration from ckan.exceptions import CkanConfigurationException @@ -74,10 +73,6 @@ def load_environment(conf: Union[Config, CKANConfig]): app_globals.reset() - # Build JavaScript translations. Must be done after plugins have - # been loaded. - build_js_translations() - # A mapping of config settings that can be overridden by env vars. # Note: Do not remove the following lines, they are used in the docs diff --git a/ckan/plugins/core.py b/ckan/plugins/core.py index 893da672830..20e49402b9e 100644 --- a/ckan/plugins/core.py +++ b/ckan/plugins/core.py @@ -10,7 +10,7 @@ from pkg_resources import iter_entry_points -from ckan.common import config +from ckan.common import config, aslist from ckan.types import SignalMapping from . import interfaces @@ -143,7 +143,7 @@ def load_all() -> None: # Clear any loaded plugins unload_all() - plugins = config['ckan.plugins'] + find_system_plugins() + plugins = aslist(config.get('ckan.plugins')) + find_system_plugins() load(*plugins) @@ -175,7 +175,9 @@ def load( if implemented_by(service, interfaces.ISignal): _connect_signals(service.get_signal_subscriptions()) output.append(service) - plugins_update() + + if plugins: + plugins_update() # Return extension instance if only one was loaded. If more that one # has been requested then a list of instances is returned in the order @@ -218,7 +220,8 @@ def unload(*plugins: str) -> None: if implemented_by(service, interfaces.ISignal): _disconnect_signals(service.get_signal_subscriptions()) - plugins_update() + if plugins: + plugins_update() def plugin_loaded(name: str) -> bool: diff --git a/ckan/tests/config/test_environment.py b/ckan/tests/config/test_environment.py index 2c0d754884d..110f4f09630 100644 --- a/ckan/tests/config/test_environment.py +++ b/ckan/tests/config/test_environment.py @@ -43,8 +43,7 @@ def test_update_config_env_vars(ckan_config): """ for env_var, value in ENV_VAR_LIST: os.environ.setdefault(env_var, value) - # plugin.load() will force the config to update - p.load() + p.plugins_update() assert ckan_config[u"solr_url"] == u"http://mynewsolrurl/solr" assert ckan_config[u"sqlalchemy.url"] == u"postgresql://mynewsqlurl/" diff --git a/doc/maintaining/installing/deployment.rst b/doc/maintaining/installing/deployment.rst index 6fc505f83ac..0695ee1c27b 100644 --- a/doc/maintaining/installing/deployment.rst +++ b/doc/maintaining/installing/deployment.rst @@ -198,8 +198,23 @@ To prevent conflicts, disable your default nginx sites and restart: sudo ln -s |nginx_config_file| /etc/nginx/sites-enabled/ckan |restart_nginx| + +----------------------------------- +7. Generate JavaScript Translations +----------------------------------- + +Some front-end features require translated strings from CKAN and its +extensions. Run this command once to extract and make these +strings available after initial installation, upgrades, enabling new +plugins or enabling new languages. + +.. parsed-literal:: + + ckan -c |ckan.ini| translation js + + ------------------------ -7. Access your CKAN site +8. Access your CKAN site ------------------------ @@ -208,7 +223,7 @@ CKAN instance. -------------------------------------- -8. Setup a worker for background jobs +9. Setup a worker for background jobs -------------------------------------- CKAN uses asynchronous :ref:`background jobs` for long tasks. These jobs are executed by a separate process which is called a :ref:`worker