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(name, 25 dockerfile_dir, 26 shell_command, 27 environ={}, 28 flake_retries=0, 29 timeout_retries=0): 30 """Creates jobspec for a task running under docker.""" 31 environ = environ.copy() 32 33 docker_args = [] 34 for k, v in list(environ.items()): 35 docker_args += ['-e', '%s=%s' % (k, v)] 36 docker_env = { 37 'DOCKERFILE_DIR': dockerfile_dir, 38 'DOCKER_RUN_SCRIPT': 'tools/run_tests/dockerize/docker_run.sh', 39 'DOCKER_RUN_SCRIPT_COMMAND': shell_command, 40 'OUTPUT_DIR': 'artifacts' 41 } 42 jobspec = jobset.JobSpec( 43 cmdline=['tools/run_tests/dockerize/build_and_run_docker.sh'] + 44 docker_args, 45 environ=docker_env, 46 shortname='build_package.%s' % (name), 47 timeout_seconds=30 * 60, 48 flake_retries=flake_retries, 49 timeout_retries=timeout_retries) 50 return jobspec 51 52 53def create_jobspec(name, 54 cmdline, 55 environ=None, 56 cwd=None, 57 shell=False, 58 flake_retries=0, 59 timeout_retries=0, 60 cpu_cost=1.0): 61 """Creates jobspec.""" 62 jobspec = jobset.JobSpec(cmdline=cmdline, 63 environ=environ, 64 cwd=cwd, 65 shortname='build_package.%s' % (name), 66 timeout_seconds=10 * 60, 67 flake_retries=flake_retries, 68 timeout_retries=timeout_retries, 69 cpu_cost=cpu_cost, 70 shell=shell) 71 return jobspec 72 73 74class CSharpPackage: 75 """Builds C# packages.""" 76 77 def __init__(self, platform): 78 self.platform = platform 79 self.labels = ['package', 'csharp', self.platform] 80 self.name = 'csharp_package_nuget_%s' % self.platform 81 self.labels += ['nuget'] 82 83 def pre_build_jobspecs(self): 84 return [] 85 86 def build_jobspec(self, inner_jobs=None): 87 del inner_jobs # arg unused as there is little opportunity for parallelizing 88 environ = { 89 'GRPC_CSHARP_BUILD_SINGLE_PLATFORM_NUGET': 90 os.getenv('GRPC_CSHARP_BUILD_SINGLE_PLATFORM_NUGET', '') 91 } 92 93 build_script = 'src/csharp/build_nuget.sh' 94 95 if self.platform == 'linux': 96 return create_docker_jobspec( 97 self.name, 98 'tools/dockerfile/test/csharp_debian11_x64', 99 build_script, 100 environ=environ) 101 else: 102 repo_root = os.path.join(os.path.dirname(os.path.abspath(__file__)), 103 '..', '..', '..') 104 environ['EXTERNAL_GIT_ROOT'] = repo_root 105 return create_jobspec(self.name, ['bash', build_script], 106 environ=environ) 107 108 def __str__(self): 109 return self.name 110 111 112class RubyPackage: 113 """Collects ruby gems created in the artifact phase""" 114 115 def __init__(self): 116 self.name = 'ruby_package' 117 self.labels = ['package', 'ruby', 'linux'] 118 119 def pre_build_jobspecs(self): 120 return [] 121 122 def build_jobspec(self, inner_jobs=None): 123 del inner_jobs # arg unused as this step simply collects preexisting artifacts 124 return create_docker_jobspec( 125 self.name, 'tools/dockerfile/grpc_artifact_centos6_x64', 126 'tools/run_tests/artifacts/build_package_ruby.sh') 127 128 129class PythonPackage: 130 """Collects python eggs and wheels created in the artifact phase""" 131 132 def __init__(self): 133 self.name = 'python_package' 134 self.labels = ['package', 'python', 'linux'] 135 136 def pre_build_jobspecs(self): 137 return [] 138 139 def build_jobspec(self, inner_jobs=None): 140 del inner_jobs # arg unused as this step simply collects preexisting artifacts 141 # since the python package build does very little, we can use virtually 142 # any image that has new-enough python, so reusing one of the images used 143 # for artifact building seems natural. 144 return create_docker_jobspec( 145 self.name, 146 'tools/dockerfile/grpc_artifact_python_manylinux2014_x64', 147 'tools/run_tests/artifacts/build_package_python.sh', 148 environ={'PYTHON': '/opt/python/cp39-cp39/bin/python'}) 149 150 151class PHPPackage: 152 """Copy PHP PECL package artifact""" 153 154 def __init__(self): 155 self.name = 'php_package' 156 self.labels = ['package', 'php', 'linux'] 157 158 def pre_build_jobspecs(self): 159 return [] 160 161 def build_jobspec(self, inner_jobs=None): 162 del inner_jobs # arg unused as this step simply collects preexisting artifacts 163 return create_docker_jobspec( 164 self.name, 'tools/dockerfile/grpc_artifact_centos6_x64', 165 'tools/run_tests/artifacts/build_package_php.sh') 166 167 168def targets(): 169 """Gets list of supported targets""" 170 return [ 171 CSharpPackage('linux'), 172 CSharpPackage('macos'), 173 CSharpPackage('windows'), 174 RubyPackage(), 175 PythonPackage(), 176 PHPPackage() 177 ] 178