diff options
author | Valentin Bartenev <vbart@nginx.com> | 2020-12-22 17:53:41 +0300 |
---|---|---|
committer | Valentin Bartenev <vbart@nginx.com> | 2020-12-22 17:53:41 +0300 |
commit | cac762ab7ef22798d0f1d0813201c0018bd589a1 (patch) | |
tree | ad094a56c7018f230ab8b83dd40085e41adb2280 | |
parent | 65295c81413cff75eddef2845f09159711e553df (diff) | |
download | unit-cac762ab7ef22798d0f1d0813201c0018bd589a1.tar.gz unit-cac762ab7ef22798d0f1d0813201c0018bd589a1.tar.bz2 |
Python: multiple values in the "path" option.
-rw-r--r-- | docs/changes.xml | 6 | ||||
-rw-r--r-- | src/nxt_application.h | 14 | ||||
-rw-r--r-- | src/nxt_conf_validation.c | 35 | ||||
-rw-r--r-- | src/nxt_main_process.c | 2 | ||||
-rw-r--r-- | src/python/nxt_python.c | 103 |
5 files changed, 124 insertions, 36 deletions
diff --git a/docs/changes.xml b/docs/changes.xml index 6bd30cab..db7a2799 100644 --- a/docs/changes.xml +++ b/docs/changes.xml @@ -9,6 +9,12 @@ date="" time="" packager="Andrei Belov <defan@nginx.com>"> +<change type="feature"> +<para> +ability to specify multiple directories in the "path" option of Python apps. +</para> +</change> + <change type="bugfix"> <para> invalid HTTP responses were generated for some unusual status codes. diff --git a/src/nxt_application.h b/src/nxt_application.h index 5632f56f..632c5632 100644 --- a/src/nxt_application.h +++ b/src/nxt_application.h @@ -47,13 +47,13 @@ typedef struct { typedef struct { - char *home; - nxt_str_t path; - nxt_str_t module; - char *callable; - nxt_str_t protocol; - uint32_t threads; - uint32_t thread_stack_size; + char *home; + nxt_conf_value_t *path; + nxt_str_t module; + char *callable; + nxt_str_t protocol; + uint32_t threads; + uint32_t thread_stack_size; } nxt_python_app_conf_t; diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c index acb2e3de..67fa3095 100644 --- a/src/nxt_conf_validation.c +++ b/src/nxt_conf_validation.c @@ -96,6 +96,10 @@ static nxt_int_t nxt_conf_vldt_return(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data); static nxt_int_t nxt_conf_vldt_proxy(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data); +static nxt_int_t nxt_conf_vldt_python_path(nxt_conf_validation_t *vldt, + nxt_conf_value_t *value, void *data); +static nxt_int_t nxt_conf_vldt_python_path_element(nxt_conf_validation_t *vldt, + nxt_conf_value_t *value); static nxt_int_t nxt_conf_vldt_python_protocol(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data); static nxt_int_t nxt_conf_vldt_threads(nxt_conf_validation_t *vldt, @@ -491,7 +495,8 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_python_members[] = { .type = NXT_CONF_VLDT_STRING, }, { .name = nxt_string("path"), - .type = NXT_CONF_VLDT_STRING, + .type = NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY, + .validator = nxt_conf_vldt_python_path, }, { .name = nxt_string("module"), .type = NXT_CONF_VLDT_STRING, @@ -1377,6 +1382,34 @@ nxt_conf_vldt_proxy(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, static nxt_int_t +nxt_conf_vldt_python_path(nxt_conf_validation_t *vldt, + nxt_conf_value_t *value, void *data) +{ + if (nxt_conf_type(value) == NXT_CONF_ARRAY) { + return nxt_conf_vldt_array_iterator(vldt, value, + &nxt_conf_vldt_python_path_element); + } + + /* NXT_CONF_STRING */ + + return NXT_OK; +} + + +static nxt_int_t +nxt_conf_vldt_python_path_element(nxt_conf_validation_t *vldt, + nxt_conf_value_t *value) +{ + if (nxt_conf_type(value) != NXT_CONF_STRING) { + return nxt_conf_vldt_error(vldt, "The \"path\" array must contain " + "only string values."); + } + + return NXT_OK; +} + + +static nxt_int_t nxt_conf_vldt_python_protocol(nxt_conf_validation_t *vldt, nxt_conf_value_t *value, void *data) { diff --git a/src/nxt_main_process.c b/src/nxt_main_process.c index 0cde435b..2916f0ab 100644 --- a/src/nxt_main_process.c +++ b/src/nxt_main_process.c @@ -182,7 +182,7 @@ static nxt_conf_map_t nxt_python_app_conf[] = { { nxt_string("path"), - NXT_CONF_MAP_STR, + NXT_CONF_MAP_PTR, offsetof(nxt_common_app_conf_t, u.python.path), }, diff --git a/src/python/nxt_python.c b/src/python/nxt_python.c index faf0c0e1..d8204937 100644 --- a/src/python/nxt_python.c +++ b/src/python/nxt_python.c @@ -24,6 +24,7 @@ typedef struct { static nxt_int_t nxt_python_start(nxt_task_t *task, nxt_process_data_t *data); +static nxt_int_t nxt_python_set_path(nxt_task_t *task, nxt_conf_value_t *value); static int nxt_python_init_threads(nxt_python_app_conf_t *c); static int nxt_python_ready_handler(nxt_unit_ctx_t *ctx); static void *nxt_python_thread_func(void *main_ctx); @@ -67,7 +68,7 @@ nxt_python_start(nxt_task_t *task, nxt_process_data_t *data) int rc; char *nxt_py_module; size_t len; - PyObject *obj, *pypath, *module; + PyObject *obj, *module; nxt_str_t proto; const char *callable; nxt_unit_ctx_t *unit_ctx; @@ -162,38 +163,18 @@ nxt_python_start(nxt_task_t *task, nxt_process_data_t *data) } nxt_py_stderr_flush = PyObject_GetAttrString(obj, "flush"); + + /* obj is a Borrowed reference. */ + obj = NULL; + if (nxt_slow_path(nxt_py_stderr_flush == NULL)) { nxt_alert(task, "Python failed to get \"flush\" attribute of " "\"sys.stderr\" object"); goto fail; } - /* obj is a Borrowed reference. */ - - if (c->path.length > 0) { - obj = PyString_FromStringAndSize((char *) c->path.start, - c->path.length); - - if (nxt_slow_path(obj == NULL)) { - nxt_alert(task, "Python failed to create string object \"%V\"", - &c->path); - goto fail; - } - - pypath = PySys_GetObject((char *) "path"); - - if (nxt_slow_path(pypath == NULL)) { - nxt_alert(task, "Python failed to get \"sys.path\" list"); - goto fail; - } - - if (nxt_slow_path(PyList_Insert(pypath, 0, obj) != 0)) { - nxt_alert(task, "Python failed to insert \"%V\" into \"sys.path\"", - &c->path); - goto fail; - } - - Py_DECREF(obj); + if (nxt_slow_path(nxt_python_set_path(task, c->path) != NXT_OK)) { + goto fail; } obj = Py_BuildValue("[s]", "unit"); @@ -317,6 +298,74 @@ fail: } +static nxt_int_t +nxt_python_set_path(nxt_task_t *task, nxt_conf_value_t *value) +{ + int ret; + PyObject *path, *sys; + nxt_str_t str; + nxt_uint_t n; + nxt_conf_value_t *array; + + if (value == NULL) { + return NXT_OK; + } + + sys = PySys_GetObject((char *) "path"); + if (nxt_slow_path(sys == NULL)) { + nxt_alert(task, "Python failed to get \"sys.path\" list"); + return NXT_ERROR; + } + + /* sys is a Borrowed reference. */ + + if (nxt_conf_type(value) == NXT_CONF_STRING) { + n = 0; + goto value_is_string; + } + + /* NXT_CONF_ARRAY */ + array = value; + + n = nxt_conf_array_elements_count(array); + + while (n != 0) { + n--; + + /* + * Insertion in front of existing paths starting from the last element + * to preserve original order while giving priority to the values + * specified in the "path" option. + */ + + value = nxt_conf_get_array_element(array, n); + + value_is_string: + + nxt_conf_get_string(value, &str); + + path = PyString_FromStringAndSize((char *) str.start, str.length); + if (nxt_slow_path(path == NULL)) { + nxt_alert(task, "Python failed to create string object \"%V\"", + &str); + return NXT_ERROR; + } + + ret = PyList_Insert(sys, 0, path); + + Py_DECREF(path); + + if (nxt_slow_path(ret != 0)) { + nxt_alert(task, "Python failed to insert \"%V\" into \"sys.path\"", + &str); + return NXT_ERROR; + } + } + + return NXT_OK; +} + + static int nxt_python_init_threads(nxt_python_app_conf_t *c) { |