Skip to content

Commit df984c3

Browse files
authored
Merge branch 'main' into feature/custom-log-formatting
2 parents c4efea9 + 364e2bf commit df984c3

File tree

11 files changed

+214
-67
lines changed

11 files changed

+214
-67
lines changed

.github/workflows/main.yml

Lines changed: 63 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@ env:
88
pip --no-cache-dir"
99

1010
jobs:
11-
tests_py27:
12-
runs-on: ubuntu-20.04
13-
container: python:2.7
11+
tests_py2x:
12+
runs-on: ubuntu-22.04
13+
container:
14+
image: python:2.7
1415
strategy:
1516
fail-fast: false
17+
matrix:
18+
toxenv: [py27, py27-configparser]
1619

1720
steps:
1821
- uses: actions/checkout@v4
@@ -21,56 +24,66 @@ jobs:
2124
run: $PIP install virtualenv tox
2225

2326
- name: Run the unit tests
24-
run: TOXENV=py27 tox
27+
run: TOXENV=${{ matrix.toxenv }} tox
2528

2629
- name: Run the end-to-end tests
27-
run: TOXENV=py27 END_TO_END=1 tox
30+
run: TOXENV=${{ matrix.toxenv }} END_TO_END=1 tox
2831

2932
tests_py34:
30-
runs-on: ubuntu-20.04
31-
strategy:
32-
fail-fast: false
33+
runs-on: ubuntu-22.04
34+
container:
35+
image: ubuntu:20.04
36+
env:
37+
LANG: C.UTF-8
3338

3439
steps:
3540
- uses: actions/checkout@v4
3641

37-
- name: Build OpenSSL 1.0.2 (required by Python 3.4)
42+
- name: Install build dependencies
3843
run: |
39-
sudo apt-get install build-essential zlib1g-dev
44+
apt-get update
45+
apt-get install -y build-essential unzip wget \
46+
libncurses5-dev libgdbm-dev libnss3-dev \
47+
libreadline-dev zlib1g-dev
4048
49+
- name: Build OpenSSL 1.0.2 (required by Python 3.4)
50+
run: |
4151
cd $RUNNER_TEMP
4252
wget https://github.com/openssl/openssl/releases/download/OpenSSL_1_0_2u/openssl-1.0.2u.tar.gz
4353
tar -xf openssl-1.0.2u.tar.gz
4454
cd openssl-1.0.2u
4555
./config --prefix=/usr/local/ssl --openssldir=/usr/local/ssl shared zlib-dynamic
4656
make
47-
sudo make install
57+
make install
4858
49-
echo CFLAGS="-I/usr/local/ssl/include $CFLAGS" >> $GITHUB_ENV
59+
echo CFLAGS="-I/usr/local/ssl/include $CFLAGS" >> $GITHUB_ENV
5060
echo LDFLAGS="-L/usr/local/ssl/lib $LDFLAGS" >> $GITHUB_ENV
5161
echo LD_LIBRARY_PATH="/usr/local/ssl/lib:$LD_LIBRARY_PATH" >> $GITHUB_ENV
5262
53-
sudo ln -s /usr/local/ssl/lib/libssl.so.1.0.0 /usr/lib/libssl.so.1.0.0
54-
sudo ln -s /usr/local/ssl/lib/libcrypto.so.1.0.0 /usr/lib/libcrypto.so.1.0.0
55-
sudo ldconfig
63+
ln -s /usr/local/ssl/lib/libssl.so.1.0.0 /usr/lib/libssl.so.1.0.0
64+
ln -s /usr/local/ssl/lib/libcrypto.so.1.0.0 /usr/lib/libcrypto.so.1.0.0
65+
ldconfig
5666
5767
- name: Build Python 3.4
5868
run: |
59-
sudo apt-get install build-essential libncurses5-dev libgdbm-dev libnss3-dev libreadline-dev zlib1g-dev
60-
6169
cd $RUNNER_TEMP
6270
wget -O cpython-3.4.10.zip https://github.com/python/cpython/archive/refs/tags/v3.4.10.zip
6371
unzip cpython-3.4.10.zip
6472
cd cpython-3.4.10
65-
./configure
73+
./configure --with-ensurepip=install
6674
make
67-
sudo make install
75+
make install
6876
6977
python3.4 --version
7078
python3.4 -c 'import ssl'
79+
pip3.4 --version
7180
72-
- name: Install dependencies
73-
run: $PIP install virtualenv==20.4.7 tox==3.28.0
81+
ln -s /usr/local/bin/python3.4 /usr/local/bin/python
82+
ln -s /usr/local/bin/pip3.4 /usr/local/bin/pip
83+
84+
- name: Install Python dependencies
85+
run: |
86+
$PIP install virtualenv==20.4.7 tox==3.14.0
7487
7588
- name: Run the unit tests
7689
run: TOXENV=py34 tox
@@ -79,40 +92,49 @@ jobs:
7992
run: TOXENV=py34 END_TO_END=1 tox
8093

8194
tests_py35:
82-
runs-on: ubuntu-20.04
95+
runs-on: ubuntu-22.04
96+
container:
97+
image: python:3.5
8398
strategy:
8499
fail-fast: false
85100

86101
steps:
87102
- uses: actions/checkout@v4
88103

89-
- name: Work around pip SSL cert verify error
90-
run: sudo $PIP config set global.trusted-host 'pypi.python.org pypi.org files.pythonhosted.org'
104+
- name: Install dependencies
105+
run: $PIP install virtualenv tox
91106

92-
- name: Set up Python 3.5
93-
uses: actions/setup-python@v5
94-
with:
95-
python-version: 3.5
107+
- name: Run the unit tests
108+
run: TOXENV=py35 tox
109+
110+
- name: Run the end-to-end tests
111+
run: TOXENV=py35 END_TO_END=1 tox
112+
113+
tests_py36:
114+
runs-on: ubuntu-22.04
115+
container:
116+
image: python:3.6
117+
strategy:
118+
fail-fast: false
119+
120+
steps:
121+
- uses: actions/checkout@v4
96122

97123
- name: Install dependencies
98124
run: $PIP install virtualenv tox
99125

100-
- name: Set variable for TOXENV based on Python version
101-
id: toxenv
102-
run: python -c 'import sys; print("TOXENV=py%d%d" % (sys.version_info.major, sys.version_info.minor))' | tee -a $GITHUB_OUTPUT
103-
104126
- name: Run the unit tests
105-
run: TOXENV=${{steps.toxenv.outputs.TOXENV}} tox
127+
run: TOXENV=py36 tox
106128

107129
- name: Run the end-to-end tests
108-
run: TOXENV=${{steps.toxenv.outputs.TOXENV}} END_TO_END=1 tox
130+
run: TOXENV=py36 END_TO_END=1 tox
109131

110132
tests_py3x:
111-
runs-on: ubuntu-20.04
133+
runs-on: ubuntu-22.04
112134
strategy:
113135
fail-fast: false
114136
matrix:
115-
python-version: [3.6, 3.7, 3.8, 3.9, "3.10", 3.11, 3.12, 3.13]
137+
python-version: [3.7, 3.8, 3.9, "3.10", 3.11, 3.12, 3.13]
116138

117139
steps:
118140
- uses: actions/checkout@v4
@@ -136,8 +158,9 @@ jobs:
136158
run: TOXENV=${{steps.toxenv.outputs.TOXENV}} END_TO_END=1 tox
137159

138160
coverage_py27:
139-
runs-on: ubuntu-20.04
140-
container: python:2.7
161+
runs-on: ubuntu-22.04
162+
container:
163+
image: python:2.7
141164
strategy:
142165
fail-fast: false
143166

@@ -151,7 +174,7 @@ jobs:
151174
run: TOXENV=cover tox
152175

153176
coverage_py3x:
154-
runs-on: ubuntu-20.04
177+
runs-on: ubuntu-22.04
155178
strategy:
156179
fail-fast: false
157180
matrix:
@@ -172,7 +195,7 @@ jobs:
172195
run: TOXENV=cover3 tox
173196

174197
docs:
175-
runs-on: ubuntu-20.04
198+
runs-on: ubuntu-22.04
176199

177200
steps:
178201
- uses: actions/checkout@v4

CHANGES.rst

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,29 @@
1-
4.3.0.dev0 (Next Release)
1+
4.4.0.dev0 (Next Release)
22
-------------------------
33

4+
- Fixed a bug where the XML-RPC method ``supervisor.getAllConfigInfo()``
5+
did not return the value of the ``autorestart`` program option.
6+
7+
- Fixed a bug where an escaped percent sign (``%%``) could not be used
8+
in ``environment=`` in the ``[supervisord]`` section of the config file.
9+
The bug did not affect ``[program:x]`` sections, where an escaped
10+
percent sign in ``environment=`` already worked. Patch by yuk1pedia.
11+
12+
- Parsing ``environment=`` in the config file now uses ``shlex`` in POSIX
13+
mode instead of legacy mode to allow for escaped quotes in the values.
14+
However, on Python 2 before 2.7.13 and Python 3 before 3.5.3, POSIX mode
15+
can't be used because of a `bug <https://bugs.python.org/issue21999>`_
16+
in ``shlex``. If ``supervisord`` is run on a Python version with the bug,
17+
it will fall back to legacy mode. Patch by Stefan Friesel.
18+
19+
- ``supervisorctl`` now reads extra files included via the ``[include]``
20+
section in ``supervisord.conf`` like ``supervisord`` does. This allows
21+
the ``[supervisorctl]`` section or ``[ctlplugin:x]`` sections to be in
22+
included files. Patch by François Granade.
23+
24+
4.3.0 (2025-08-23)
25+
------------------
26+
427
- Fixed a bug where the poller would not unregister a closed
528
file descriptor under some circumstances, which caused excessive
629
polling, resulting in higher CPU usage. Patch by aftersnow.
@@ -16,10 +39,13 @@
1639
- On Python 3.8 and later, ``setuptools`` is no longer a runtime
1740
dependency. Patch by Ofek Lev.
1841

19-
- ``supervisorctl`` now reads extra files included via the ``[include]``
20-
section in ``supervisord.conf`` like ``supervisord`` does. This allows
21-
the ``[supervisorctl]`` section or ``[ctlplugin:x]`` sections to be in
22-
included files. Patch by François Granade.
42+
- On Python versions before 3.8, ``setuptools`` is still a runtime
43+
dependency (for ``pkg_resources``) but it is no longer declared in
44+
``setup.py`` as such. This is because adding a conditional dependency
45+
with an environment marker (``setuptools; python_version < '3.8'``)
46+
breaks installation in some scenarios, e.g. ``setup.py install`` or
47+
older versions of ``pip``. Ensure that ``setuptools`` is installed
48+
if using Python before 3.8.
2349

2450
4.2.5 (2022-12-23)
2551
------------------

docs/installing.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ to be the root user to install Supervisor successfully using
2222

2323
You can also install supervisor in a virtualenv via ``pip``.
2424

25+
.. note::
26+
27+
If installing on a Python version before 3.8, first ensure that the
28+
``setuptools`` package is installed because it is a runtime
29+
dependency of Supervisor.
30+
2531
Internet-Installing Without Pip
2632
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2733

@@ -39,6 +45,12 @@ finally install Supervisor itself.
3945
need to be the root user to successfully invoke ``python
4046
setup.py install``.
4147

48+
.. note::
49+
50+
The ``setuptools`` package is required to run ``python setup.py install``.
51+
On Python versions before 3.8, ``setuptools`` is also a runtime
52+
dependency of Supervisor.
53+
4254
Installing To A System Without Internet Access
4355
----------------------------------------------
4456

@@ -63,6 +75,12 @@ Finally, run supervisor's ``python setup.py install``.
6375
need to be the root user to invoke ``python setup.py install``
6476
successfully for each package.
6577

78+
.. note::
79+
80+
The ``setuptools`` package is required to run ``python setup.py install``.
81+
On Python versions before 3.8, ``setuptools`` is also a runtime
82+
dependency of Supervisor.
83+
6684
Installing a Distribution Package
6785
---------------------------------
6886

setup.py

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,19 @@
2222
elif (3, 0) < py_version < (3, 4):
2323
raise RuntimeError('On Python 3, Supervisor requires Python 3.4 or later')
2424

25-
# setuptools is required as a runtime dependency only on
26-
# Python < 3.8. See the comments in supervisor/compat.py.
27-
requires = [
28-
"setuptools; python_version < '3.8'",
29-
]
30-
31-
tests_require = []
32-
testing_extras = tests_require + [
33-
'pytest',
34-
'pytest-cov',
35-
]
25+
# setuptools is required as a runtime dependency only on Python < 3.8.
26+
# See the comments in supervisor/compat.py. An environment marker
27+
# like "setuptools; python_version < '3.8'" is not used here because
28+
# it breaks installation via "python setup.py install". See also the
29+
# discussion at: https://github.com/Supervisor/supervisor/issues/1692
30+
if py_version < (3, 8):
31+
try:
32+
import pkg_resources
33+
except ImportError:
34+
raise RuntimeError(
35+
"On Python < 3.8, Supervisor requires setuptools as a runtime"
36+
" dependency because pkg_resources is used to load plugins"
37+
)
3638

3739
from setuptools import setup, find_packages
3840
here = os.path.abspath(os.path.dirname(__file__))
@@ -92,14 +94,12 @@
9294
author="Chris McDonough",
9395
author_email="chrism@plope.com",
9496
packages=find_packages(),
95-
install_requires=requires,
97+
install_requires=[],
9698
extras_require={
97-
'testing': testing_extras,
99+
'test': ['pytest', 'pytest-cov']
98100
},
99-
tests_require=tests_require,
100101
include_package_data=True,
101102
zip_safe=False,
102-
test_suite="supervisor.tests",
103103
entry_points={
104104
'console_scripts': [
105105
'supervisord = supervisor.supervisord:main',

supervisor/compat.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,26 @@ def is_text_stream(stream):
150150
except ImportError: # pragma: no cover
151151
from HTMLParser import HTMLParser
152152

153+
# Begin check for working shlex posix mode
154+
155+
# https://github.com/Supervisor/supervisor/issues/328
156+
# https://github.com/Supervisor/supervisor/issues/873
157+
# https://bugs.python.org/issue21999
158+
159+
from shlex import shlex as _shlex
160+
161+
_shlex_posix_expectations = {
162+
'foo="",bar=a': ['foo', '=', '', ',', 'bar', '=', 'a'],
163+
"'')abc": ['', ')', 'abc']
164+
}
165+
166+
shlex_posix_works = all(
167+
list(_shlex(_input, posix=True)) == _expected
168+
for _input, _expected in _shlex_posix_expectations.items()
169+
)
170+
171+
# End check for working shlex posix mode
172+
153173
# Begin importlib/setuptools compatibility code
154174

155175
# Supervisor used pkg_resources (a part of setuptools) to load package

supervisor/datatypes.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import socket
66
import shlex
77

8+
from supervisor.compat import shlex_posix_works
89
from supervisor.compat import urlparse
910
from supervisor.compat import long
1011
from supervisor.loggers import getLevelNumByDescription
@@ -68,7 +69,7 @@ def dict_of_key_value_pairs(arg):
6869
""" parse KEY=val,KEY2=val2 into {'KEY':'val', 'KEY2':'val2'}
6970
Quotes can be used to allow commas in the value
7071
"""
71-
lexer = shlex.shlex(str(arg))
72+
lexer = shlex.shlex(str(arg), posix=shlex_posix_works)
7273
lexer.wordchars += '/.+-():'
7374

7475
tokens = list(lexer)
@@ -81,7 +82,12 @@ def dict_of_key_value_pairs(arg):
8182
if len(k_eq_v) != 3 or k_eq_v[1] != '=':
8283
raise ValueError(
8384
"Unexpected end of key/value pairs in value '%s'" % arg)
84-
D[k_eq_v[0]] = k_eq_v[2].strip('\'"')
85+
86+
k, v = k_eq_v[0], k_eq_v[2]
87+
if not shlex_posix_works:
88+
v = v.strip('\'"')
89+
90+
D[k] = v
8591
i += 4
8692
return D
8793

0 commit comments

Comments
 (0)