Files
opensearch-pyd/utils/build-dists.py
T

301 lines
10 KiB
Python
Raw Normal View History

# SPDX-License-Identifier: Apache-2.0
#
# The OpenSearch Contributors require contributions made to
# this file be licensed under the Apache-2.0 license or a
# compatible open source license.
#
# Modifications Copyright OpenSearch Contributors. See
# GitHub history for details.
#
# Licensed to Elasticsearch B.V. under one or more contributor
# license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright
# ownership. Elasticsearch B.V. licenses this file to you 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.
2020-06-24 14:25:28 -05:00
"""A command line tool for building and verifying releases
2021-09-16 14:59:29 +05:30
Can be used for building both 'opensearchpy' and 'opensearchpyX' dists.
2020-06-24 14:25:28 -05:00
Only requires 'name' in 'setup.py' and the directory to be changed.
"""
import contextlib
import os
import re
import shlex
2020-06-24 14:25:28 -05:00
import shutil
import sys
import tempfile
2020-06-24 14:25:28 -05:00
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
tmp_dir = None
@contextlib.contextmanager
def set_tmp_dir():
global tmp_dir
tmp_dir = tempfile.mkdtemp()
yield tmp_dir
shutil.rmtree(tmp_dir)
tmp_dir = None
def run(*argv, expect_exit_code=0):
global tmp_dir
if tmp_dir is None:
os.chdir(base_dir)
else:
os.chdir(tmp_dir)
cmd = " ".join(shlex.quote(x) for x in argv)
print("$ " + cmd)
exit_code = os.system(cmd)
if exit_code != expect_exit_code:
print(
"Command exited incorrectly: should have been %d was %d"
% (expect_exit_code, exit_code)
)
exit(exit_code or 1)
def test_dist(dist):
with set_tmp_dir() as tmp_dir:
2021-09-17 02:21:57 +05:30
dist_name = re.match(
r"^(opensearchpy\d*)-",
os.path.basename(dist)
.replace("opensearch-py", "opensearchpy")
.replace("opensearch_py", "opensearchpy"),
).group(1)
2020-06-24 14:25:28 -05:00
# Build the venv and install the dist
run("python", "-m", "venv", os.path.join(tmp_dir, "venv"))
venv_python = os.path.join(tmp_dir, "venv/bin/python")
run(venv_python, "-m", "pip", "install", "-U", "pip", "mypy")
2020-06-24 14:25:28 -05:00
run(venv_python, "-m", "pip", "install", dist)
# Test the sync namespaces
2021-08-13 15:51:50 +05:30
run(venv_python, "-c", f"from {dist_name} import OpenSearch")
2020-06-24 14:25:28 -05:00
run(
venv_python,
"-c",
f"from {dist_name}.helpers import scan, bulk, streaming_bulk, reindex",
)
2021-08-13 15:51:50 +05:30
run(venv_python, "-c", f"from {dist_name} import OpenSearch")
2020-06-24 14:25:28 -05:00
run(
venv_python,
"-c",
f"from {dist_name}.helpers import scan, bulk, streaming_bulk, reindex",
)
# Ensure that async is not available yet
run(
venv_python,
"-c",
2021-08-13 15:51:50 +05:30
f"from {dist_name} import AsyncOpenSearch",
2020-06-24 14:25:28 -05:00
expect_exit_code=256,
)
run(
venv_python,
"-c",
f"from {dist_name}.helpers import async_scan, async_bulk, async_streaming_bulk, async_reindex",
expect_exit_code=256,
)
# Install aiohttp and see that async is now available
run(venv_python, "-m", "pip", "install", "aiohttp")
2021-08-13 15:51:50 +05:30
run(venv_python, "-c", f"from {dist_name} import AsyncOpenSearch")
2020-08-20 07:18:23 -05:00
run(
venv_python,
"-c",
f"from {dist_name}.helpers import async_scan, async_bulk, async_streaming_bulk, async_reindex",
)
2020-06-24 14:25:28 -05:00
# Only need to test 'async_types' for non-aliased package
# since 'aliased_types' tests both async and sync.
2021-09-16 14:59:29 +05:30
if dist_name == "opensearchpy":
run(
venv_python,
"-m",
"mypy",
"--strict",
2021-09-16 14:59:29 +05:30
os.path.join(base_dir, "test_opensearchpy/test_types/async_types.py"),
)
2020-06-24 14:25:28 -05:00
# Ensure that the namespaces are correct for the dist
for suffix in ("", "1", "2", "5", "6", "7", "8", "9", "10"):
2021-09-16 14:59:29 +05:30
distx_name = f"opensearchpy{suffix}"
2020-06-24 14:25:28 -05:00
run(
venv_python,
"-c",
f"import {distx_name}",
expect_exit_code=256 if distx_name != dist_name else 0,
)
2021-09-16 14:59:29 +05:30
# Check that sync types work for 'opensearchpy' and
# that aliased types work for 'opensearchpyX'
if dist_name == "opensearchpy":
run(
venv_python,
"-m",
"mypy",
"--strict",
2021-09-16 14:59:29 +05:30
os.path.join(base_dir, "test_opensearchpy/test_types/sync_types.py"),
)
else:
run(
venv_python,
"-m",
"mypy",
"--strict",
2021-09-16 14:59:29 +05:30
os.path.join(base_dir, "test_opensearchpy/test_types/aliased_types.py"),
)
2020-06-24 14:25:28 -05:00
# Uninstall the dist, see that we can't import things anymore
run(
venv_python,
"-m",
"pip",
"uninstall",
"--yes",
dist_name.replace("opensearchpy", "opensearch-py"),
)
2020-06-24 14:25:28 -05:00
run(
venv_python,
"-c",
2021-08-13 15:51:50 +05:30
f"from {dist_name} import OpenSearch",
2020-06-24 14:25:28 -05:00
expect_exit_code=256,
)
def main():
2021-09-16 14:59:29 +05:30
run("git", "checkout", "--", "setup.py", "opensearchpy/")
run("rm", "-rf", "build/", "dist/*", "*.egg-info", ".eggs")
2020-06-24 14:25:28 -05:00
# Grab the major version to be used as a suffix.
2021-09-16 14:59:29 +05:30
version_path = os.path.join(base_dir, "opensearchpy/_version.py")
with open(version_path) as f:
version = re.search(
r"^__versionstr__\s+=\s+[\"\']([^\"\']+)[\"\']", f.read(), re.M
).group(1)
major_version = version.split(".")[0]
# If we're handed a version from the build manager we
# should check that the version is correct or write
# a new one.
if len(sys.argv) >= 2:
# 'build_version' is what the release manager wants,
# 'expect_version' is what we're expecting to compare
# the package version to before building the dists.
build_version = expect_version = sys.argv[1]
# Any prefixes in the version specifier mean we're making
# a pre-release which will modify __versionstr__ locally
# and not produce a git tag.
if any(x in build_version for x in ("-SNAPSHOT", "-rc", "-alpha", "-beta")):
# If a snapshot, then we add '+dev'
if "-SNAPSHOT" in build_version:
version = version + "+dev"
# alpha/beta/rc -> aN/bN/rcN
else:
pre_number = re.search(r"-(a|b|rc)(?:lpha|eta|)(\d+)$", expect_version)
version = version + pre_number.group(1) + pre_number.group(2)
expect_version = re.sub(
r"(?:-(?:SNAPSHOT|alpha\d+|beta\d+|rc\d+))+$", "", expect_version
)
if expect_version.endswith(".x"):
expect_version = expect_version[:-1]
# For snapshots we ensure that the version in the package
# at least *starts* with the version. This is to support
# build_version='7.x-SNAPSHOT'.
if not version.startswith(expect_version):
print(
"Version of package (%s) didn't match the "
"expected release version (%s)" % (version, build_version)
)
exit(1)
# A release that will be tagged, we want
# there to be no '+dev', etc.
elif expect_version != version:
print(
"Version of package (%s) didn't match the "
"expected release version (%s)" % (version, build_version)
)
exit(1)
for suffix in ("", major_version):
run("rm", "-rf", "build/", "*.egg-info", ".eggs")
# Rename the module to fit the suffix.
shutil.move(
2021-09-16 14:59:29 +05:30
os.path.join(base_dir, "opensearchpy"),
os.path.join(base_dir, "opensearchpy%s" % suffix),
)
2021-09-16 14:59:29 +05:30
# Ensure that the version within 'opensearchpy/_version.py' is correct.
version_path = os.path.join(base_dir, f"opensearchpy{suffix}/_version.py")
with open(version_path) as f:
version_data = f.read()
version_data = re.sub(
r"__versionstr__ = \"[^\"]+\"",
'__versionstr__ = "%s"' % version,
version_data,
)
with open(version_path, "w") as f:
f.truncate()
f.write(version_data)
# Rewrite setup.py with the new name.
setup_py_path = os.path.join(base_dir, "setup.py")
with open(setup_py_path) as f:
setup_py = f.read()
with open(setup_py_path, "w") as f:
f.truncate()
2021-09-17 02:21:57 +05:30
assert 'package_name = "opensearch-py"' in setup_py
f.write(
setup_py.replace(
2021-09-17 02:21:57 +05:30
'package_name = "opensearch-py"',
'package_name = "opensearch-py%s"' % suffix,
)
)
# Build the sdist/wheels
run("python", "setup.py", "sdist", "bdist_wheel")
# Clean up everything.
2021-09-16 14:59:29 +05:30
run("git", "checkout", "--", "setup.py", "opensearchpy/")
if suffix:
2021-09-16 14:59:29 +05:30
run("rm", "-rf", "opensearchpy%s/" % suffix)
# Test everything that got created
dists = os.listdir(os.path.join(base_dir, "dist"))
assert len(dists) == 4
for dist in dists:
2020-06-24 14:25:28 -05:00
test_dist(os.path.join(base_dir, "dist", dist))
os.system("chmod a+w dist/*")
2020-06-24 14:25:28 -05:00
# After this run 'python -m twine upload dist/*'
print(
"\n\n"
"===============================\n\n"
" * Releases are ready! *\n\n"
"$ python -m twine upload dist/*\n\n"
"==============================="
)
if __name__ == "__main__":
main()