build_docker_image.py
1 # SPDX-FileCopyrightText: 2023 LakeSoul Contributors 2 # 3 # SPDX-License-Identifier: Apache-2.0 4 5 import io 6 import os 7 import re 8 import json 9 import subprocess 10 11 12 class ManylinuxDockerImageBuilder(object): 13 def __init__(self): 14 self._dockerfile_dir = self._get_dockerfile_dir() 15 self._project_root_dir = self._get_project_root_dir() 16 self._pyproject_toml_path = self._get_pyproject_toml_path() 17 self._manylinux_image_name = self._get_manylinux_image_name() 18 19 def _get_dockerfile_dir(self): 20 dir_path = os.path.dirname(os.path.realpath(__file__)) 21 return dir_path 22 23 def _get_project_root_dir(self): 24 dir_path = os.path.dirname(os.path.realpath(__file__)) 25 dir_path = os.path.dirname(os.path.dirname(dir_path)) 26 return dir_path 27 28 def _get_pyproject_toml_path(self): 29 file_path = os.path.join(self._project_root_dir, "pyproject.toml") 30 return file_path 31 32 def _get_manylinux_image_name(self): 33 with io.open(self._pyproject_toml_path) as fin: 34 text = fin.read() 35 match = re.search('^manylinux-x86_64-image = "(.+)"$', text, re.M) 36 if match is None: 37 message = "fail to read manylinux image name " 38 message += "from %r" % self._pyproject_toml_path 39 raise RuntimeError(message) 40 image_name = match.group(1) 41 return image_name 42 43 def _parse_args(self): 44 import argparse 45 46 parser = argparse.ArgumentParser(description="build manylinux docker image") 47 parser.add_argument( 48 "-f", 49 "--force-rebuild", 50 action="store_true", 51 help="force rebuilding of the docker image", 52 ) 53 args = parser.parse_args() 54 self._force_rebuild = args.force_rebuild 55 56 def _docker_image_exists(self): 57 args = ["docker", "images", "--format", "json"] 58 output = subprocess.check_output(args) 59 for line in output.splitlines(): 60 image = json.loads(line) 61 name = "%s:%s" % (image["Repository"], image["Tag"]) 62 if name == self._manylinux_image_name: 63 return True 64 return False 65 66 def _handle_proxy(self, args): 67 import os 68 69 http_proxy = os.environ.get("http_proxy") 70 https_proxy = os.environ.get("https_proxy") 71 no_proxy = os.environ.get("no_proxy") 72 if http_proxy is not None or https_proxy is not None or no_proxy is not None: 73 args += ["--network", "host"] 74 if http_proxy is not None: 75 args += ["--build-arg", "http_proxy=%s" % http_proxy] 76 if https_proxy is not None: 77 args += ["--build-arg", "https_proxy=%s" % https_proxy] 78 if no_proxy is not None: 79 args += ["--build-arg", "no_proxy=%s" % no_proxy] 80 81 def _handle_rust_version(self, args): 82 print(self._project_root_dir) 83 with open(f"{self._project_root_dir}/rust/rust-toolchain.toml") as f: 84 match = re.search(r'channel\s*=\s*"([^"]+)"', f.read()) 85 if match: 86 channel_value = match.group(1) 87 args += ["--build-arg", "RUST_VRESION=%s" % channel_value] 88 else: 89 raise RuntimeError("get rust version failed") 90 91 def _build_docker_image(self): 92 args = ["docker", "build"] 93 self._handle_proxy(args) 94 self._handle_rust_version(args) 95 args += ["--tag", self._manylinux_image_name] 96 args += [self._dockerfile_dir] 97 subprocess.check_call(args) 98 99 def run(self): 100 self._parse_args() 101 if not self._docker_image_exists() or self._force_rebuild: 102 self._build_docker_image() 103 104 105 def main(): 106 builder = ManylinuxDockerImageBuilder() 107 builder.run() 108 109 110 if __name__ == "__main__": 111 main()