2016-01-07 05:26:29 +01:00
|
|
|
# Copyright 2015, 2016 OpenMarket Ltd
|
2017-03-13 18:27:51 +01:00
|
|
|
# Copyright 2017 Vector Creations Ltd
|
2018-04-26 13:34:40 +02:00
|
|
|
# Copyright 2018 New Vector Ltd
|
2015-04-24 11:35:29 +02:00
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
|
2015-01-08 18:07:28 +01:00
|
|
|
import logging
|
2018-12-21 15:37:26 +01:00
|
|
|
|
|
|
|
from pkg_resources import DistributionNotFound, VersionConflict, get_distribution
|
2015-01-08 18:07:28 +01:00
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
2018-12-21 15:37:26 +01:00
|
|
|
|
|
|
|
# REQUIREMENTS is a simple list of requirement specifiers[1], and must be
|
|
|
|
# installed. It is passed to setup() as install_requires in setup.py.
|
2018-04-26 13:34:40 +02:00
|
|
|
#
|
2018-12-21 15:37:26 +01:00
|
|
|
# CONDITIONAL_REQUIREMENTS is the optional dependencies, represented as a dict
|
|
|
|
# of lists. The dict key is the optional dependency name and can be passed to
|
|
|
|
# pip when installing. The list is a series of requirement specifiers[1] to be
|
|
|
|
# installed when that optional dependency requirement is specified. It is passed
|
|
|
|
# to setup() as extras_require in setup.py
|
2018-04-26 13:34:40 +02:00
|
|
|
#
|
|
|
|
# [1] https://pip.pypa.io/en/stable/reference/pip_install/#requirement-specifiers.
|
|
|
|
|
2018-12-21 15:37:26 +01:00
|
|
|
REQUIREMENTS = [
|
|
|
|
"jsonschema>=2.5.1",
|
|
|
|
"frozendict>=1",
|
|
|
|
"unpaddedbase64>=1.1.0",
|
|
|
|
"canonicaljson>=1.1.3",
|
|
|
|
"signedjson>=1.0.0",
|
|
|
|
"pynacl>=1.2.1",
|
|
|
|
"service_identity>=16.0.0",
|
2019-01-17 15:00:23 +01:00
|
|
|
|
|
|
|
# our logcontext handling relies on the ability to cancel inlineCallbacks
|
|
|
|
# (https://twistedmatrix.com/trac/ticket/4632) which landed in Twisted 18.7.
|
|
|
|
"Twisted>=18.7.0",
|
|
|
|
|
2018-12-21 15:37:26 +01:00
|
|
|
"treq>=15.1",
|
2018-09-06 13:53:15 +02:00
|
|
|
# Twisted has required pyopenssl 16.0 since about Twisted 16.6.
|
2018-12-21 15:37:26 +01:00
|
|
|
"pyopenssl>=16.0.0",
|
|
|
|
"pyyaml>=3.11",
|
|
|
|
"pyasn1>=0.1.9",
|
|
|
|
"pyasn1-modules>=0.0.7",
|
|
|
|
"daemonize>=2.3.1",
|
|
|
|
"bcrypt>=3.1.0",
|
|
|
|
"pillow>=3.1.2",
|
|
|
|
"sortedcontainers>=1.4.4",
|
|
|
|
"psutil>=2.0.0",
|
2019-01-16 09:44:22 +01:00
|
|
|
"pymacaroons>=0.13.0",
|
2019-01-16 09:41:29 +01:00
|
|
|
"msgpack>=0.5.0",
|
2018-12-21 15:37:26 +01:00
|
|
|
"phonenumbers>=8.2.0",
|
|
|
|
"six>=1.10",
|
2018-10-03 18:15:35 +02:00
|
|
|
# prometheus_client 0.4.0 changed the format of counter metrics
|
|
|
|
# (cf https://github.com/matrix-org/synapse/issues/4001)
|
2018-12-21 15:37:26 +01:00
|
|
|
"prometheus_client>=0.0.18,<0.4.0",
|
2019-01-17 15:00:23 +01:00
|
|
|
|
2018-09-25 11:43:39 +02:00
|
|
|
# we use attr.s(slots), which arrived in 16.0.0
|
2019-01-17 15:00:23 +01:00
|
|
|
# Twisted 18.7.0 requires attrs>=17.4.0
|
|
|
|
"attrs>=17.4.0",
|
|
|
|
|
2018-12-21 15:37:26 +01:00
|
|
|
"netaddr>=0.7.18",
|
2019-05-03 19:30:13 +02:00
|
|
|
|
|
|
|
# requests is a transitive dep of treq, and urlib3 is a transitive dep
|
|
|
|
# of requests, as well as of sentry-sdk.
|
|
|
|
#
|
|
|
|
# As of requests 2.21, requests does not yet support urllib3 1.25.
|
|
|
|
# (If we do not pin it here, pip will give us the latest urllib3
|
|
|
|
# due to the dep via sentry-sdk.)
|
|
|
|
"urllib3<1.25",
|
2018-12-21 15:37:26 +01:00
|
|
|
]
|
2018-06-05 16:13:57 +02:00
|
|
|
|
2015-03-17 12:45:37 +01:00
|
|
|
CONDITIONAL_REQUIREMENTS = {
|
2019-01-07 11:14:31 +01:00
|
|
|
"email.enable_notifs": ["Jinja2>=2.9", "bleach>=1.4.2"],
|
2018-12-21 15:37:26 +01:00
|
|
|
"matrix-synapse-ldap3": ["matrix-synapse-ldap3>=0.1"],
|
|
|
|
"postgres": ["psycopg2>=2.6"],
|
2019-01-07 11:14:31 +01:00
|
|
|
|
|
|
|
# ConsentResource uses select_autoescape, which arrived in jinja 2.9
|
|
|
|
"resources.consent": ["Jinja2>=2.9"],
|
|
|
|
|
2019-01-23 09:39:06 +01:00
|
|
|
# ACME support is required to provision TLS certificates from authorities
|
|
|
|
# that use the protocol, such as Let's Encrypt.
|
|
|
|
"acme": ["txacme>=0.9.2"],
|
|
|
|
|
2018-12-21 15:37:26 +01:00
|
|
|
"saml2": ["pysaml2>=4.5.0"],
|
|
|
|
"url_preview": ["lxml>=3.5.0"],
|
2019-01-17 14:55:37 +01:00
|
|
|
"test": ["mock>=2.0", "parameterized"],
|
2019-02-12 14:55:58 +01:00
|
|
|
"sentry": ["sentry-sdk>=0.7.2"],
|
2015-03-17 12:45:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-12-21 15:37:26 +01:00
|
|
|
def list_requirements():
|
|
|
|
deps = set(REQUIREMENTS)
|
|
|
|
for opt in CONDITIONAL_REQUIREMENTS.values():
|
|
|
|
deps = set(opt) | deps
|
2015-01-08 18:07:28 +01:00
|
|
|
|
2018-12-21 15:37:26 +01:00
|
|
|
return list(deps)
|
2015-02-10 17:30:48 +01:00
|
|
|
|
2015-02-02 18:22:40 +01:00
|
|
|
|
2018-12-21 15:37:26 +01:00
|
|
|
class DependencyException(Exception):
|
2019-01-07 11:14:31 +01:00
|
|
|
@property
|
|
|
|
def message(self):
|
|
|
|
return "\n".join([
|
|
|
|
"Missing Requirements: %s" % (", ".join(self.dependencies),),
|
|
|
|
"To install run:",
|
|
|
|
" pip install --upgrade --force %s" % (" ".join(self.dependencies),),
|
|
|
|
"",
|
|
|
|
])
|
|
|
|
|
2018-12-21 15:37:26 +01:00
|
|
|
@property
|
|
|
|
def dependencies(self):
|
|
|
|
for i in self.args[0]:
|
|
|
|
yield '"' + i + '"'
|
2016-11-15 12:22:29 +01:00
|
|
|
|
2015-02-02 18:22:40 +01:00
|
|
|
|
2019-01-07 11:14:31 +01:00
|
|
|
def check_requirements(for_feature=None, _get_distribution=get_distribution):
|
2018-12-21 15:37:26 +01:00
|
|
|
deps_needed = []
|
|
|
|
errors = []
|
2015-01-08 18:07:28 +01:00
|
|
|
|
2019-01-07 11:14:31 +01:00
|
|
|
if for_feature:
|
|
|
|
reqs = CONDITIONAL_REQUIREMENTS[for_feature]
|
|
|
|
else:
|
|
|
|
reqs = REQUIREMENTS
|
|
|
|
|
|
|
|
for dependency in reqs:
|
2018-12-21 15:37:26 +01:00
|
|
|
try:
|
|
|
|
_get_distribution(dependency)
|
|
|
|
except VersionConflict as e:
|
|
|
|
deps_needed.append(dependency)
|
|
|
|
errors.append(
|
|
|
|
"Needed %s, got %s==%s"
|
|
|
|
% (dependency, e.dist.project_name, e.dist.version)
|
2015-01-08 18:07:28 +01:00
|
|
|
)
|
2018-12-21 15:37:26 +01:00
|
|
|
except DistributionNotFound:
|
|
|
|
deps_needed.append(dependency)
|
|
|
|
errors.append("Needed %s but it was not installed" % (dependency,))
|
2015-01-08 18:07:28 +01:00
|
|
|
|
2019-01-07 11:14:31 +01:00
|
|
|
if not for_feature:
|
|
|
|
# Check the optional dependencies are up to date. We allow them to not be
|
|
|
|
# installed.
|
|
|
|
OPTS = sum(CONDITIONAL_REQUIREMENTS.values(), [])
|
|
|
|
|
|
|
|
for dependency in OPTS:
|
|
|
|
try:
|
|
|
|
_get_distribution(dependency)
|
2019-01-23 18:41:59 +01:00
|
|
|
except VersionConflict as e:
|
2019-01-07 11:14:31 +01:00
|
|
|
deps_needed.append(dependency)
|
2019-01-23 18:41:59 +01:00
|
|
|
errors.append(
|
|
|
|
"Needed optional %s, got %s==%s"
|
|
|
|
% (dependency, e.dist.project_name, e.dist.version)
|
|
|
|
)
|
2019-01-07 11:14:31 +01:00
|
|
|
except DistributionNotFound:
|
|
|
|
# If it's not found, we don't care
|
|
|
|
pass
|
2015-02-10 17:30:48 +01:00
|
|
|
|
2018-12-21 15:37:26 +01:00
|
|
|
if deps_needed:
|
|
|
|
for e in errors:
|
2019-01-07 11:14:31 +01:00
|
|
|
logging.error(e)
|
2018-12-21 15:37:26 +01:00
|
|
|
|
|
|
|
raise DependencyException(deps_needed)
|
2015-02-02 18:22:40 +01:00
|
|
|
|
2016-11-15 12:22:29 +01:00
|
|
|
|
2015-02-02 18:22:40 +01:00
|
|
|
if __name__ == "__main__":
|
|
|
|
import sys
|
2018-12-21 15:37:26 +01:00
|
|
|
|
2015-02-02 18:22:40 +01:00
|
|
|
sys.stdout.writelines(req + "\n" for req in list_requirements())
|