1# Copyright 2020 The gRPC Authors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14"""Generates grpc-prefixed packages using template renderer. 15 16To use this script, please use 3.7+ interpreter. This script is work-directory 17agnostic. A quick executable command: 18 19 python3 tools/distrib/python/grpc_prefixed/generate.py 20""" 21 22import dataclasses 23import datetime 24import logging 25import os 26import shutil 27import subprocess 28import sys 29 30import jinja2 31 32WORK_PATH = os.path.realpath(os.path.dirname(__file__)) 33LICENSE = os.path.join(WORK_PATH, "../../../../LICENSE") 34BUILD_PATH = os.path.join(WORK_PATH, "build") 35DIST_PATH = os.path.join(WORK_PATH, "dist") 36 37env = jinja2.Environment( 38 loader=jinja2.FileSystemLoader(os.path.join(WORK_PATH, "templates")) 39) 40 41LOGGER = logging.getLogger(__name__) 42POPEN_TIMEOUT_S = datetime.timedelta(minutes=1).total_seconds() 43 44 45@dataclasses.dataclass 46class PackageMeta: 47 """Meta-info of a PyPI package.""" 48 49 name: str 50 name_long: str 51 destination_package: str 52 version: str = "1.0.0" 53 54 55def clean() -> None: 56 try: 57 shutil.rmtree(BUILD_PATH) 58 except FileNotFoundError: 59 pass 60 61 try: 62 shutil.rmtree(DIST_PATH) 63 except FileNotFoundError: 64 pass 65 66 67def generate_package(meta: PackageMeta) -> None: 68 # Makes package directory 69 package_path = os.path.join(BUILD_PATH, meta.name) 70 os.makedirs(package_path, exist_ok=True) 71 72 # Copy license 73 shutil.copyfile(LICENSE, os.path.join(package_path, "LICENSE")) 74 75 # Generates source code 76 for template_name in env.list_templates(): 77 template = env.get_template(template_name) 78 with open( 79 os.path.join(package_path, template_name.replace(".template", "")), 80 "w", 81 ) as f: 82 f.write(template.render(dataclasses.asdict(meta))) 83 84 # Creates wheel 85 job = subprocess.Popen( 86 [ 87 sys.executable, 88 os.path.join(package_path, "setup.py"), 89 "sdist", 90 "--dist-dir", 91 DIST_PATH, 92 ], 93 cwd=package_path, 94 stdout=subprocess.PIPE, 95 stderr=subprocess.STDOUT, 96 ) 97 outs, _ = job.communicate(timeout=POPEN_TIMEOUT_S) 98 99 # Logs result 100 if job.returncode != 0: 101 LOGGER.error("Wheel creation failed with %d", job.returncode) 102 LOGGER.error(outs) 103 else: 104 LOGGER.info("Package <%s> generated", meta.name) 105 106 107def main(): 108 clean() 109 110 generate_package( 111 PackageMeta( 112 name="grpc", name_long="gRPC Python", destination_package="grpcio" 113 ) 114 ) 115 116 generate_package( 117 PackageMeta( 118 name="grpc-status", 119 name_long="gRPC Rich Error Status", 120 destination_package="grpcio-status", 121 ) 122 ) 123 124 generate_package( 125 PackageMeta( 126 name="grpc-channelz", 127 name_long="gRPC Channel Tracing", 128 destination_package="grpcio-channelz", 129 ) 130 ) 131 132 generate_package( 133 PackageMeta( 134 name="grpc-tools", 135 name_long="ProtoBuf Code Generator", 136 destination_package="grpcio-tools", 137 ) 138 ) 139 140 generate_package( 141 PackageMeta( 142 name="grpc-reflection", 143 name_long="gRPC Reflection", 144 destination_package="grpcio-reflection", 145 ) 146 ) 147 148 generate_package( 149 PackageMeta( 150 name="grpc-testing", 151 name_long="gRPC Testing Utility", 152 destination_package="grpcio-testing", 153 ) 154 ) 155 156 generate_package( 157 PackageMeta( 158 name="grpc-health-checking", 159 name_long="gRPC Health Checking", 160 destination_package="grpcio-health-checking", 161 ) 162 ) 163 164 generate_package( 165 PackageMeta( 166 name="grpc-csds", 167 name_long="gRPC Client Status Discovery Service", 168 destination_package="grpcio-csds", 169 ) 170 ) 171 172 generate_package( 173 PackageMeta( 174 name="grpc-admin", 175 name_long="gRPC Admin Interface", 176 destination_package="grpcio-admin", 177 ) 178 ) 179 180 181if __name__ == "__main__": 182 logging.basicConfig(level=logging.INFO) 183 main() 184