1#!/usr/bin/env python3 2# Copyright 2016 gRPC authors. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15"""Definition of targets to build distribution packages.""" 16 17import os.path 18import sys 19 20sys.path.insert(0, os.path.abspath("..")) 21import python_utils.jobset as jobset 22 23 24def create_docker_jobspec( 25 name, 26 dockerfile_dir, 27 shell_command, 28 environ={}, 29 flake_retries=0, 30 timeout_retries=0, 31): 32 """Creates jobspec for a task running under docker.""" 33 environ = environ.copy() 34 35 docker_args = [] 36 for k, v in list(environ.items()): 37 docker_args += ["-e", "%s=%s" % (k, v)] 38 docker_env = { 39 "DOCKERFILE_DIR": dockerfile_dir, 40 "DOCKER_RUN_SCRIPT": "tools/run_tests/dockerize/docker_run.sh", 41 "DOCKER_RUN_SCRIPT_COMMAND": shell_command, 42 "OUTPUT_DIR": "artifacts", 43 } 44 jobspec = jobset.JobSpec( 45 cmdline=["tools/run_tests/dockerize/build_and_run_docker.sh"] 46 + docker_args, 47 environ=docker_env, 48 shortname="build_package.%s" % (name), 49 timeout_seconds=30 * 60, 50 flake_retries=flake_retries, 51 timeout_retries=timeout_retries, 52 ) 53 return jobspec 54 55 56def create_jobspec( 57 name, 58 cmdline, 59 environ=None, 60 cwd=None, 61 shell=False, 62 flake_retries=0, 63 timeout_retries=0, 64 cpu_cost=1.0, 65): 66 """Creates jobspec.""" 67 jobspec = jobset.JobSpec( 68 cmdline=cmdline, 69 environ=environ, 70 cwd=cwd, 71 shortname="build_package.%s" % (name), 72 timeout_seconds=10 * 60, 73 flake_retries=flake_retries, 74 timeout_retries=timeout_retries, 75 cpu_cost=cpu_cost, 76 shell=shell, 77 ) 78 return jobspec 79 80 81class CSharpPackage: 82 """Builds C# packages.""" 83 84 def __init__(self, platform): 85 self.platform = platform 86 self.labels = ["package", "csharp", self.platform] 87 self.name = "csharp_package_nuget_%s" % self.platform 88 self.labels += ["nuget"] 89 90 def pre_build_jobspecs(self): 91 return [] 92 93 def build_jobspec(self, inner_jobs=None): 94 del inner_jobs # arg unused as there is little opportunity for parallelizing 95 environ = { 96 "GRPC_CSHARP_BUILD_SINGLE_PLATFORM_NUGET": os.getenv( 97 "GRPC_CSHARP_BUILD_SINGLE_PLATFORM_NUGET", "" 98 ) 99 } 100 101 build_script = "src/csharp/build_nuget.sh" 102 103 if self.platform == "linux": 104 return create_docker_jobspec( 105 self.name, 106 "tools/dockerfile/test/csharp_debian11_x64", 107 build_script, 108 environ=environ, 109 ) 110 else: 111 repo_root = os.path.join( 112 os.path.dirname(os.path.abspath(__file__)), "..", "..", ".." 113 ) 114 environ["EXTERNAL_GIT_ROOT"] = repo_root 115 return create_jobspec( 116 self.name, ["bash", build_script], environ=environ 117 ) 118 119 def __str__(self): 120 return self.name 121 122 123class RubyPackage: 124 """Collects ruby gems created in the artifact phase""" 125 126 def __init__(self): 127 self.name = "ruby_package" 128 self.labels = ["package", "ruby", "linux"] 129 130 def pre_build_jobspecs(self): 131 return [] 132 133 def build_jobspec(self, inner_jobs=None): 134 del inner_jobs # arg unused as this step simply collects preexisting artifacts 135 return create_docker_jobspec( 136 self.name, 137 "tools/dockerfile/grpc_artifact_centos6_x64", 138 "tools/run_tests/artifacts/build_package_ruby.sh", 139 ) 140 141 142class PythonPackage: 143 """Collects python eggs and wheels created in the artifact phase""" 144 145 def __init__(self): 146 self.name = "python_package" 147 self.labels = ["package", "python", "linux"] 148 149 def pre_build_jobspecs(self): 150 return [] 151 152 def build_jobspec(self, inner_jobs=None): 153 del inner_jobs # arg unused as this step simply collects preexisting artifacts 154 # since the python package build does very little, we can use virtually 155 # any image that has new-enough python, so reusing one of the images used 156 # for artifact building seems natural. 157 return create_docker_jobspec( 158 self.name, 159 "tools/dockerfile/grpc_artifact_python_manylinux2014_x64", 160 "tools/run_tests/artifacts/build_package_python.sh", 161 environ={"PYTHON": "/opt/python/cp39-cp39/bin/python"}, 162 ) 163 164 165class PHPPackage: 166 """Copy PHP PECL package artifact""" 167 168 def __init__(self): 169 self.name = "php_package" 170 self.labels = ["package", "php", "linux"] 171 172 def pre_build_jobspecs(self): 173 return [] 174 175 def build_jobspec(self, inner_jobs=None): 176 del inner_jobs # arg unused as this step simply collects preexisting artifacts 177 return create_docker_jobspec( 178 self.name, 179 "tools/dockerfile/grpc_artifact_centos6_x64", 180 "tools/run_tests/artifacts/build_package_php.sh", 181 ) 182 183 184def targets(): 185 """Gets list of supported targets""" 186 return [ 187 CSharpPackage("linux"), 188 CSharpPackage("macos"), 189 CSharpPackage("windows"), 190 RubyPackage(), 191 PythonPackage(), 192 PHPPackage(), 193 ] 194