# Copyright 2020 The gRPC Authors # # 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. """Generates grpc-prefixed packages using template renderer. To use this script, please use 3.7+ interpreter. This script is work-directory agnostic. A quick executable command: python3 tools/distrib/python/grpc_prefixed/generate.py """ import dataclasses import datetime import logging import os import shutil import subprocess import sys import jinja2 WORK_PATH = os.path.realpath(os.path.dirname(__file__)) LICENSE = os.path.join(WORK_PATH, '../../../../LICENSE') BUILD_PATH = os.path.join(WORK_PATH, 'build') DIST_PATH = os.path.join(WORK_PATH, 'dist') env = jinja2.Environment( loader=jinja2.FileSystemLoader(os.path.join(WORK_PATH, 'templates'))) LOGGER = logging.getLogger(__name__) POPEN_TIMEOUT_S = datetime.timedelta(minutes=1).total_seconds() @dataclasses.dataclass class PackageMeta: """Meta-info of a PyPI package.""" name: str name_long: str destination_package: str version: str = '1.0.0' def clean() -> None: try: shutil.rmtree(BUILD_PATH) except FileNotFoundError: pass try: shutil.rmtree(DIST_PATH) except FileNotFoundError: pass def generate_package(meta: PackageMeta) -> None: # Makes package directory package_path = os.path.join(BUILD_PATH, meta.name) os.makedirs(package_path, exist_ok=True) # Copy license shutil.copyfile(LICENSE, os.path.join(package_path, 'LICENSE')) # Generates source code for template_name in env.list_templates(): template = env.get_template(template_name) with open( os.path.join(package_path, template_name.replace('.template', '')), 'w') as f: f.write(template.render(dataclasses.asdict(meta))) # Creates wheel job = subprocess.Popen([ sys.executable, os.path.join(package_path, 'setup.py'), 'sdist', '--dist-dir', DIST_PATH ], cwd=package_path, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) outs, _ = job.communicate(timeout=POPEN_TIMEOUT_S) # Logs result if job.returncode != 0: LOGGER.error('Wheel creation failed with %d', job.returncode) LOGGER.error(outs) else: LOGGER.info('Package <%s> generated', meta.name) def main(): clean() generate_package( PackageMeta(name='grpc', name_long='gRPC Python', destination_package='grpcio')) generate_package( PackageMeta(name='grpc-status', name_long='gRPC Rich Error Status', destination_package='grpcio-status')) generate_package( PackageMeta(name='grpc-channelz', name_long='gRPC Channel Tracing', destination_package='grpcio-channelz')) generate_package( PackageMeta(name='grpc-tools', name_long='ProtoBuf Code Generator', destination_package='grpcio-tools')) generate_package( PackageMeta(name='grpc-reflection', name_long='gRPC Reflection', destination_package='grpcio-reflection')) generate_package( PackageMeta(name='grpc-testing', name_long='gRPC Testing Utility', destination_package='grpcio-testing')) generate_package( PackageMeta(name='grpc-health-checking', name_long='gRPC Health Checking', destination_package='grpcio-health-checking')) generate_package( PackageMeta(name='grpc-csds', name_long='gRPC Client Status Discovery Service', destination_package='grpcio-csds')) generate_package( PackageMeta(name='grpc-admin', name_long='gRPC Admin Interface', destination_package='grpcio-admin')) if __name__ == "__main__": logging.basicConfig(level=logging.INFO) main()