Compare commits

...

5 Commits

Author SHA1 Message Date
Brad Warren
6f6521226f update httplib2 and jinja 2021-03-15 14:41:20 -07:00
Brad Warren
70d974b3cc update comments 2021-03-15 14:38:57 -07:00
Brad Warren
4e718804d0 Rename pipstrap constraints to requirements 2021-03-11 16:22:29 -08:00
Brad Warren
4a51935b63 rename dev constraints to reqs 2021-03-11 16:20:47 -08:00
Brad Warren
55357fd316 certbot constraints to reqs 2021-03-11 15:58:00 -08:00
10 changed files with 99 additions and 78 deletions

View File

@@ -85,8 +85,8 @@ parts:
snapcraftctl build
override-pull: |
snapcraftctl pull
python3 "${SNAPCRAFT_PART_SRC}/tools/strip_hashes.py" "${SNAPCRAFT_PART_SRC}/tools/certbot_constraints.txt" | grep -v python-augeas >> "${SNAPCRAFT_PART_SRC}/snap-constraints.txt"
python3 "${SNAPCRAFT_PART_SRC}/tools/strip_hashes.py" "${SNAPCRAFT_PART_SRC}/tools/pipstrap_constraints.txt" >> "${SNAPCRAFT_PART_SRC}/snap-constraints.txt"
python3 "${SNAPCRAFT_PART_SRC}/tools/strip_hashes.py" "${SNAPCRAFT_PART_SRC}/tools/certbot_requirements.txt" | grep -v python-augeas >> "${SNAPCRAFT_PART_SRC}/snap-constraints.txt"
python3 "${SNAPCRAFT_PART_SRC}/tools/strip_hashes.py" "${SNAPCRAFT_PART_SRC}/tools/pipstrap_requirements.txt" >> "${SNAPCRAFT_PART_SRC}/snap-constraints.txt"
echo "$(python3 "${SNAPCRAFT_PART_SRC}/tools/merge_requirements.py" "${SNAPCRAFT_PART_SRC}/snap-constraints.txt")" > "${SNAPCRAFT_PART_SRC}/snap-constraints.txt"
snapcraftctl set-version `grep -oP "__version__ = '\K.*(?=')" "${SNAPCRAFT_PART_SRC}/certbot/certbot/__init__.py"`
shared-metadata:

View File

@@ -12,8 +12,8 @@ sudo $BOOTSTRAP_SCRIPT
# We strip the hashes because the venv creation script includes unhashed
# constraints in the commands given to pip and the mix of hashed and unhashed
# packages makes pip error out.
python3 tools/strip_hashes.py tools/pipstrap_constraints.txt > constraints.txt
python3 tools/strip_hashes.py tools/certbot_constraints.txt > requirements.txt
python3 tools/strip_hashes.py tools/pipstrap_requirements.txt > constraints.txt
python3 tools/strip_hashes.py tools/certbot_requirements.txt > requirements.txt
# We pin cryptography to 3.1.1 and pyOpenSSL to 19.1.0 specifically for CentOS 7 / RHEL 7
# because these systems ship only with OpenSSL 1.0.2, and this OpenSSL version support has been

View File

@@ -1,57 +1,62 @@
# This is the flattened list of pinned packages to build certbot deployable artifacts.
# This is the flattened list of pinned packages to use as constraints for pip
# when building deployable Certbot artifacts. Despite the file being used as
# constraints, you may want to include "requirements.txt" in the filename so
# https://docs.github.com/en/github/visualizing-repository-data-with-graphs/about-the-dependency-graph#supported-package-ecosystems
# for more info.
#
# To generate this, do (with docker and package hashin installed):
# ```
# tools/rebuild_certbot_contraints.py \
# tools/certbot_constraints.txt
# tools/certbot_requirements.txt
# ```
# If you want to update a single dependency, run commands similar to these:
# ```
# pip install hashin
# hashin -r dependency-requirements.txt cryptography==1.5.2
# ```
ConfigArgParse==1.2.3 \
--hash=sha256:edd17be986d5c1ba2e307150b8e5f5107aba125f3574dddd02c85d5cdcfd37dc
ConfigArgParse==1.4 \
--hash=sha256:abef9ff44fb0091f0e3bb2ee7e5b26a02b5b62d45408a5272a9bd461f5b59b4b
certifi==2020.12.5 \
--hash=sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c \
--hash=sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830
cffi==1.14.4 \
--hash=sha256:00a1ba5e2e95684448de9b89888ccd02c98d512064b4cb987d48f4b40aa0421e \
--hash=sha256:00e28066507bfc3fe865a31f325c8391a1ac2916219340f87dfad602c3e48e5d \
--hash=sha256:045d792900a75e8b1e1b0ab6787dd733a8190ffcf80e8c8ceb2fb10a29ff238a \
--hash=sha256:0638c3ae1a0edfb77c6765d487fee624d2b1ee1bdfeffc1f0b58c64d149e7eec \
--hash=sha256:105abaf8a6075dc96c1fe5ae7aae073f4696f2905fde6aeada4c9d2926752362 \
--hash=sha256:155136b51fd733fa94e1c2ea5211dcd4c8879869008fc811648f16541bf99668 \
--hash=sha256:1a465cbe98a7fd391d47dce4b8f7e5b921e6cd805ef421d04f5f66ba8f06086c \
--hash=sha256:1d2c4994f515e5b485fd6d3a73d05526aa0fcf248eb135996b088d25dfa1865b \
--hash=sha256:2c24d61263f511551f740d1a065eb0212db1dbbbbd241db758f5244281590c06 \
--hash=sha256:51a8b381b16ddd370178a65360ebe15fbc1c71cf6f584613a7ea08bfad946698 \
--hash=sha256:594234691ac0e9b770aee9fcdb8fa02c22e43e5c619456efd0d6c2bf276f3eb2 \
--hash=sha256:5cf4be6c304ad0b6602f5c4e90e2f59b47653ac1ed9c662ed379fe48a8f26b0c \
--hash=sha256:64081b3f8f6f3c3de6191ec89d7dc6c86a8a43911f7ecb422c60e90c70be41c7 \
--hash=sha256:6bc25fc545a6b3d57b5f8618e59fc13d3a3a68431e8ca5fd4c13241cd70d0009 \
--hash=sha256:798caa2a2384b1cbe8a2a139d80734c9db54f9cc155c99d7cc92441a23871c03 \
--hash=sha256:7c6b1dece89874d9541fc974917b631406233ea0440d0bdfbb8e03bf39a49b3b \
--hash=sha256:7ef7d4ced6b325e92eb4d3502946c78c5367bc416398d387b39591532536734e \
--hash=sha256:840793c68105fe031f34d6a086eaea153a0cd5c491cde82a74b420edd0a2b909 \
--hash=sha256:8d6603078baf4e11edc4168a514c5ce5b3ba6e3e9c374298cb88437957960a53 \
--hash=sha256:9cc46bc107224ff5b6d04369e7c595acb700c3613ad7bcf2e2012f62ece80c35 \
--hash=sha256:9f7a31251289b2ab6d4012f6e83e58bc3b96bd151f5b5262467f4bb6b34a7c26 \
--hash=sha256:9ffb888f19d54a4d4dfd4b3f29bc2c16aa4972f1c2ab9c4ab09b8ab8685b9c2b \
--hash=sha256:a5ed8c05548b54b998b9498753fb9cadbfd92ee88e884641377d8a8b291bcc01 \
--hash=sha256:a7711edca4dcef1a75257b50a2fbfe92a65187c47dab5a0f1b9b332c5919a3fb \
--hash=sha256:af5c59122a011049aad5dd87424b8e65a80e4a6477419c0c1015f73fb5ea0293 \
--hash=sha256:b18e0a9ef57d2b41f5c68beefa32317d286c3d6ac0484efd10d6e07491bb95dd \
--hash=sha256:b4e248d1087abf9f4c10f3c398896c87ce82a9856494a7155823eb45a892395d \
--hash=sha256:ba4e9e0ae13fc41c6b23299545e5ef73055213e466bd107953e4a013a5ddd7e3 \
--hash=sha256:c6332685306b6417a91b1ff9fae889b3ba65c2292d64bd9245c093b1b284809d \
--hash=sha256:d5ff0621c88ce83a28a10d2ce719b2ee85635e85c515f12bac99a95306da4b2e \
--hash=sha256:d9efd8b7a3ef378dd61a1e77367f1924375befc2eba06168b6ebfa903a5e59ca \
--hash=sha256:df5169c4396adc04f9b0a05f13c074df878b6052430e03f50e68adf3a57aa28d \
--hash=sha256:ebb253464a5d0482b191274f1c8bf00e33f7e0b9c66405fbffc61ed2c839c775 \
--hash=sha256:ec80dc47f54e6e9a78181ce05feb71a0353854cc26999db963695f950b5fb375 \
--hash=sha256:f032b34669220030f905152045dfa27741ce1a6db3324a5bc0b96b6c7420c87b \
--hash=sha256:f60567825f791c6f8a592f3c6e3bd93dd2934e3f9dac189308426bd76b00ef3b \
--hash=sha256:f803eaa94c2fcda012c047e62bc7a51b0bdabda1cad7a92a522694ea2d76e49f
cffi==1.14.5 \
--hash=sha256:005a36f41773e148deac64b08f233873a4d0c18b053d37da83f6af4d9087b813 \
--hash=sha256:0857f0ae312d855239a55c81ef453ee8fd24136eaba8e87a2eceba644c0d4c06 \
--hash=sha256:1071534bbbf8cbb31b498d5d9db0f274f2f7a865adca4ae429e147ba40f73dea \
--hash=sha256:158d0d15119b4b7ff6b926536763dc0714313aa59e320ddf787502c70c4d4bee \
--hash=sha256:1f436816fc868b098b0d63b8920de7d208c90a67212546d02f84fe78a9c26396 \
--hash=sha256:2894f2df484ff56d717bead0a5c2abb6b9d2bf26d6960c4604d5c48bbc30ee73 \
--hash=sha256:29314480e958fd8aab22e4a58b355b629c59bf5f2ac2492b61e3dc06d8c7a315 \
--hash=sha256:34eff4b97f3d982fb93e2831e6750127d1355a923ebaeeb565407b3d2f8d41a1 \
--hash=sha256:35f27e6eb43380fa080dccf676dece30bef72e4a67617ffda586641cd4508d49 \
--hash=sha256:3d3dd4c9e559eb172ecf00a2a7517e97d1e96de2a5e610bd9b68cea3925b4892 \
--hash=sha256:43e0b9d9e2c9e5d152946b9c5fe062c151614b262fda2e7b201204de0b99e482 \
--hash=sha256:48e1c69bbacfc3d932221851b39d49e81567a4d4aac3b21258d9c24578280058 \
--hash=sha256:51182f8927c5af975fece87b1b369f722c570fe169f9880764b1ee3bca8347b5 \
--hash=sha256:58e3f59d583d413809d60779492342801d6e82fefb89c86a38e040c16883be53 \
--hash=sha256:5de7970188bb46b7bf9858eb6890aad302577a5f6f75091fd7cdd3ef13ef3045 \
--hash=sha256:65fa59693c62cf06e45ddbb822165394a288edce9e276647f0046e1ec26920f3 \
--hash=sha256:69e395c24fc60aad6bb4fa7e583698ea6cc684648e1ffb7fe85e3c1ca131a7d5 \
--hash=sha256:6c97d7350133666fbb5cf4abdc1178c812cb205dc6f41d174a7b0f18fb93337e \
--hash=sha256:6e4714cc64f474e4d6e37cfff31a814b509a35cb17de4fb1999907575684479c \
--hash=sha256:72d8d3ef52c208ee1c7b2e341f7d71c6fd3157138abf1a95166e6165dd5d4369 \
--hash=sha256:8ae6299f6c68de06f136f1f9e69458eae58f1dacf10af5c17353eae03aa0d827 \
--hash=sha256:8b198cec6c72df5289c05b05b8b0969819783f9418e0409865dac47288d2a053 \
--hash=sha256:99cd03ae7988a93dd00bcd9d0b75e1f6c426063d6f03d2f90b89e29b25b82dfa \
--hash=sha256:9cf8022fb8d07a97c178b02327b284521c7708d7c71a9c9c355c178ac4bbd3d4 \
--hash=sha256:9de2e279153a443c656f2defd67769e6d1e4163952b3c622dcea5b08a6405322 \
--hash=sha256:9e93e79c2551ff263400e1e4be085a1210e12073a31c2011dbbda14bda0c6132 \
--hash=sha256:9ff227395193126d82e60319a673a037d5de84633f11279e336f9c0f189ecc62 \
--hash=sha256:a465da611f6fa124963b91bf432d960a555563efe4ed1cc403ba5077b15370aa \
--hash=sha256:ad17025d226ee5beec591b52800c11680fca3df50b8b29fe51d882576e039ee0 \
--hash=sha256:afb29c1ba2e5a3736f1c301d9d0abe3ec8b86957d04ddfa9d7a6a42b9367e396 \
--hash=sha256:b85eb46a81787c50650f2392b9b4ef23e1f126313b9e0e9013b35c15e4288e2e \
--hash=sha256:bb89f306e5da99f4d922728ddcd6f7fcebb3241fc40edebcb7284d7514741991 \
--hash=sha256:cbde590d4faaa07c72bf979734738f328d239913ba3e043b1e98fe9a39f8b2b6 \
--hash=sha256:cd2868886d547469123fadc46eac7ea5253ea7fcb139f12e1dfc2bbd406427d1 \
--hash=sha256:d42b11d692e11b6634f7613ad8df5d6d5f8875f5d48939520d351007b3c13406 \
--hash=sha256:f2d45f97ab6bb54753eab54fffe75aaf3de4ff2341c9daee1987ee1837636f1d \
--hash=sha256:fd78e5fee591709f32ef6edb9a015b4aa1a5022598e36227500c8f4e02328d9c
chardet==4.0.0 \
--hash=sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa \
--hash=sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5
@@ -78,9 +83,9 @@ distro==1.5.0 \
idna==2.10 \
--hash=sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6 \
--hash=sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0
josepy==1.6.0 \
--hash=sha256:0aab1c3ceffe045e7fd5bcfe7685e27e9d2758518d9ba7116b5de34087e70bf5 \
--hash=sha256:65f077fc5902aca1e140ddb000e7abb081d5fb8421db60b6071076ef81c5bd27
josepy==1.7.0 \
--hash=sha256:84c9d202093236fddbfaefc3137a476a9863d43c054268863a9d6727a22f1317 \
--hash=sha256:d265414fa16d7a8b7a1d1833b4ebb19a22bd0deae5d44413cf9040fd8491d85a
parsedatetime==2.6 \
--hash=sha256:4cb368fbb18a0b7231f4d76119165451c8d2e35951455dfee97c62a87b04d455 \
--hash=sha256:cb96edd7016872f58479e35879294258c71437195760746faffedb692aef000b
@@ -110,9 +115,9 @@ requests-toolbelt==0.9.1 \
six==1.15.0 \
--hash=sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259 \
--hash=sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced
urllib3==1.26.3 \
--hash=sha256:1b465e494e3e0d8939b50680403e3aedaa2bc434b7d5af64dfd3c958d7f5ae80 \
--hash=sha256:de3eedaad74a2683334e282005cd8d7f22f4d55fa690a2a1020a416cb0a47e73
urllib3==1.26.4 \
--hash=sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df \
--hash=sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937
zope.component==4.6.2 \
--hash=sha256:607628e4c84f7887a69a958542b5c304663e726b73aba0882e3a3f059bff14f3 \
--hash=sha256:91628918218b3e6f6323de2a7b845e09ddc5cae131c034896c051b084bba3c92

View File

@@ -1,7 +1,13 @@
# Specifies Python package versions for development and building Docker images.
# It includes in particular packages not specified in letsencrypt-auto's requirements file.
# Some dev package versions specified here may be overridden by higher level constraints
# files during tests (eg. tools/certbot_constraints.txt).
# Specifies Python package versions for development and building Docker
# images. It includes in particular packages not specified in Certbot's
# requirements file. Some dev package versions specified here may be
# overridden by higher level requirements files during tests (eg.
# tools/certbot_requirements.txt). Because of that and the fact that this file
# is used as constraints rather than requirements, you should include any
# package that may be required here. This file is named "requirements" rather
# than "constraints" so that it is scanned by GitHub. See
# https://docs.github.com/en/github/visualizing-repository-data-with-graphs/about-the-dependency-graph#supported-package-ecosystems
# for more info.
alabaster==0.7.10
apacheconfig==0.3.2
apipkg==1.4
@@ -39,7 +45,7 @@ future==0.16.0
futures==3.3.0
filelock==3.0.12
google-api-python-client==1.5.5
httplib2==0.18.1
httplib2==0.19.0
imagesize==0.7.1
importlib-metadata==0.23
ipdb==0.12.3
@@ -48,7 +54,7 @@ ipython-genutils==0.2.0
isodate==0.6.0
isort==4.3.21
jedi==0.17.1
Jinja2==2.9.6
Jinja2==2.11.3
jmespath==0.9.4
josepy==1.1.0
jsonpickle==2.0.0

View File

@@ -1,10 +1,10 @@
#!/usr/bin/env python
# pip installs packages using pinned package versions. If CERTBOT_OLDEST is set
# to 1, a combination of tools/oldest_constraints.txt,
# tools/dev_constraints.txt, and local-oldest-requirements.txt contained in the
# tools/dev_requirements.txt, and local-oldest-requirements.txt contained in the
# top level of the package's directory is used, otherwise, a combination of
# certbot-auto's requirements file and tools/dev_constraints.txt is used. The
# other file always takes precedence over tools/dev_constraints.txt. If
# certbot-auto's requirements file and tools/dev_requirements.txt is used. The
# other file always takes precedence over tools/dev_requirements.txt. If
# CERTBOT_OLDEST is set, this script must be run with `-e <package-name>` and
# no other arguments.
@@ -57,10 +57,10 @@ def certbot_oldest_processing(tools_path, args, test_constraints):
def certbot_normal_processing(tools_path, test_constraints):
repo_path = os.path.dirname(tools_path)
certbot_requirements = os.path.normpath(os.path.join(
repo_path, 'tools/certbot_constraints.txt'))
repo_path, 'tools/certbot_requirements.txt'))
with open(certbot_requirements, 'r') as fd:
certbot_reqs = fd.readlines()
with open(os.path.join(tools_path, 'pipstrap_constraints.txt'), 'r') as fd:
with open(os.path.join(tools_path, 'pipstrap_requirements.txt'), 'r') as fd:
pipstrap_reqs = fd.readlines()
with open(test_constraints, 'w') as fd:
data_certbot = "\n".join(strip_hashes.process_entries(certbot_reqs))
@@ -74,11 +74,11 @@ def merge_requirements(tools_path, requirements, test_constraints, all_constrain
# Indeed version retained for a given package will be the last version
# found when following all requirements in the given order.
# Here is the order by increasing priority:
# 1) The general development constraints (tools/dev_constraints.txt)
# 1) The general development constraints (tools/dev_requirements.txt)
# 2) The general tests constraints (oldest_requirements.txt or
# certbot_constraints.txt + pipstrap's constraints for the normal processing)
# certbot_requirements.txt + pipstrap's constraints for the normal processing)
# 3) The local requirement file, typically local-oldest-requirement in oldest tests
files = [os.path.join(tools_path, 'dev_constraints.txt'), test_constraints]
files = [os.path.join(tools_path, 'dev_requirements.txt'), test_constraints]
if requirements:
files.append(requirements)
merged_requirements = merge_module.main(*files)

View File

@@ -4,7 +4,7 @@ import os
import pip_install
_REQUIREMENTS_PATH = os.path.join(os.path.dirname(__file__), "pipstrap_constraints.txt")
_REQUIREMENTS_PATH = os.path.join(os.path.dirname(__file__), "pipstrap_requirements.txt")
def main():

View File

@@ -1,4 +1,9 @@
# Constraints for pipstrap.py
# Requirements file for pipstrap.py
#
# It is important that this file's name includes "requirements.txt" so that it
# is scanned by GitHub. See
# https://docs.github.com/en/github/visualizing-repository-data-with-graphs/about-the-dependency-graph#supported-package-ecosystems
# for more info.
#
# We include the hashes of the packages here for extra verification of
# the packages downloaded from PyPI. This is especially valuable in our

View File

@@ -4,12 +4,12 @@ Gather and consolidate the up-to-date dependencies available and required to ins
on various Linux distributions. It generates a requirements file contained the pinned and hashed
versions, ready to be used by pip to install the certbot dependencies.
This script is typically used to update the certbot_constraints.txt file.
This script is typically used to update the certbot_requirements.txt file.
To achieve its purpose, this script will start a certbot installation with unpinned dependencies,
then gather them, on various distributions started as Docker containers.
Usage: tools/rebuild_certbot_constraints.py new_requirements.txt
Usage: tools/rebuild_certbot_requirements.py new_requirements.txt
NB1: Docker must be installed on the machine running this script.
NB2: Python library 'hashin' must be installed on the machine running this script.
@@ -42,7 +42,7 @@ AUTHORITATIVE_CONSTRAINTS = {
'cryptography': '3.3.2',
}
# ./certbot/tools/rebuild_certbot_constraints.py (2 levels from certbot root path)
# ./certbot/tools/rebuild_certbot_requirements.py (2 levels from certbot root path)
CERTBOT_REPO_PATH = dirname(dirname(abspath(__file__)))
# The script will be used to gather dependencies for a given distribution.
@@ -205,11 +205,16 @@ def _write_requirements(dest_file, requirements, conflicts):
print('===> Calculating hashes for the requirement file.')
_write_to(dest_file, '''\
# This is the flattened list of pinned packages to build certbot deployable artifacts.
# This is the flattened list of pinned packages to use as constraints for pip
# when building deployable Certbot artifacts. Despite the file being used as
# constraints, you may want to include "requirements.txt" in the filename so
# https://docs.github.com/en/github/visualizing-repository-data-with-graphs/about-the-dependency-graph#supported-package-ecosystems
# for more info.
#
# To generate this, do (with docker and package hashin installed):
# ```
# tools/rebuild_certbot_contraints.py \\
# tools/certbot_constraints.txt
# tools/certbot_requirements.txt
# ```
# If you want to update a single dependency, run commands similar to these:
# ```

View File

@@ -9,8 +9,8 @@ for PLUGIN_PATH in "${CERTBOT_DIR}"/certbot-dns-*; do
bash "${CERTBOT_DIR}"/tools/snap/generate_dnsplugins_snapcraft.sh $PLUGIN_PATH
bash "${CERTBOT_DIR}"/tools/snap/generate_dnsplugins_postrefreshhook.sh $PLUGIN_PATH
# Create constraints file
"${CERTBOT_DIR}"/tools/merge_requirements.py tools/dev_constraints.txt \
<("${CERTBOT_DIR}"/tools/strip_hashes.py tools/certbot_constraints.txt) \
<("${CERTBOT_DIR}"/tools/strip_hashes.py tools/pipstrap_constraints.txt) \
"${CERTBOT_DIR}"/tools/merge_requirements.py tools/dev_requirements.txt \
<("${CERTBOT_DIR}"/tools/strip_hashes.py tools/certbot_requirements.txt) \
<("${CERTBOT_DIR}"/tools/strip_hashes.py tools/pipstrap_requirements.txt) \
> "${PLUGIN_PATH}"/snap-constraints.txt
done

View File

@@ -79,8 +79,8 @@ def _prepare_build_tools(venv_path, venv_python, repo_path):
@contextlib.contextmanager
def _prepare_constraints(repo_path):
reqs_certbot = os.path.join(repo_path, 'tools', 'certbot_constraints.txt')
reqs_pipstrap = os.path.join(repo_path, 'tools', 'pipstrap_constraints.txt')
reqs_certbot = os.path.join(repo_path, 'tools', 'certbot_requirements.txt')
reqs_pipstrap = os.path.join(repo_path, 'tools', 'pipstrap_requirements.txt')
constraints_certbot = subprocess.check_output(
[sys.executable, os.path.join(repo_path, 'tools', 'strip_hashes.py'), reqs_certbot],
universal_newlines=True)