github.com/yoheimuta/protolint@v0.49.8-0.20240515023657-4ecaebb7575d/bdist/py/setup.py (about) 1 #!/usr/bin/env python3 2 3 import contextlib 4 import hashlib 5 import logging 6 import os 7 import pathlib 8 import shutil 9 import subprocess 10 import sys 11 import zipfile 12 13 14 @contextlib.contextmanager 15 def as_cwd(path): 16 """Changes working directory and returns to previous on exit.""" 17 prev_cwd = pathlib.Path.cwd() 18 os.chdir(path) 19 try: 20 yield 21 finally: 22 os.chdir(prev_cwd) 23 24 25 def clear_dir(path): 26 if path.is_dir(): 27 for e in path.glob("**/*"): 28 if e.is_dir(): 29 logger.debug("Clearing entries from %s", e) 30 clear_dir(e) 31 else: 32 logger.debug("Removing file %s", e) 33 e.unlink() 34 logger.debug("Removing directory %s", path) 35 path.rmdir() 36 37 38 logger = logging.getLogger("BUILD") 39 logger.setLevel(logging.INFO) 40 logger.addHandler(logging.StreamHandler(sys.stdout)) 41 42 file_dir: pathlib.Path = pathlib.Path(os.path.dirname(__file__)) 43 bdist = file_dir / "_bdist" 44 wheel = file_dir / "_wheel" 45 46 if wheel.is_dir(): 47 clear_dir(wheel) 48 49 bdist.mkdir(exist_ok=True, parents=True) 50 wheel.mkdir(exist_ok=True, parents=True) 51 52 logger.info("Building files from %s", file_dir) 53 repo_root = file_dir / ".." / ".." 54 license_file = repo_root / "LICENSE" 55 readme_rst = file_dir / "ReadMe.rst" 56 57 logger.info("Using repository root %s", repo_root) 58 59 dist = repo_root / "dist" 60 61 logger.info("Using previously files from %s", dist) 62 63 cp: subprocess.CompletedProcess = subprocess.run(["git", "describe", "--tag"], capture_output=True) 64 version_id = cp.stdout.decode("utf8").lstrip("v").rstrip("\n") 65 del cp 66 67 logger.info("Assuming version is %s", version_id) 68 69 ap_map: dict[str, str] = { 70 "darwin_amd64_v1": "macosx_10_0_x86_64", 71 "darwin_arm64": "macosx_10_0_arm64", 72 "linux_amd64_v1": "manylinux2014_x86_64", 73 "linux_arm64": "manylinux2014_aarch64", 74 "linux_arm_7": "manylinux2014_armv7l", 75 "windows_amd64_v1": "win_amd64", 76 "windows_arm64": "win_arm64", 77 } 78 79 executables = {"protolint", "protoc-gen-protolint"} 80 81 PY_TAG = "py2.py3" 82 ABI_TAG = "none" 83 84 package_name = "protolint-bin" 85 86 87 for arch_platform in ap_map.keys(): 88 tag = f"{PY_TAG}-{ABI_TAG}-{ap_map[arch_platform]}" 89 logger.info("Packing files for %s using tag %s", arch_platform, tag) 90 suffix = ".exe" if "windows" in arch_platform else "" 91 92 pdir = bdist / arch_platform 93 clear_dir(pdir) 94 pdir.mkdir(exist_ok=True, parents=True) 95 96 p_executables = [dist / f"{exe}_{arch_platform}" / f"{exe}{suffix}" for exe in executables] 97 98 file_name = package_name.replace('-', '_') 99 100 logger.debug("Creating wheel data folder") 101 dataFolder = pdir / f"{file_name}-{version_id}.data" 102 logger.debug("Creating wheel data folder") 103 distInfoFolder = pdir / f"{file_name}-{version_id}.dist-info" 104 105 dataFolder.mkdir(parents=True, exist_ok=True) 106 distInfoFolder.mkdir(parents=True, exist_ok=True) 107 108 with as_cwd(pdir): 109 logger.debug("Creating scripts folder") 110 scripts = dataFolder / "scripts" 111 scripts.mkdir(parents=True, exist_ok=True) 112 for p in p_executables: 113 logger.debug("Copying executable %s to scripts folder %s", p, scripts) 114 shutil.copy(p, scripts) 115 116 logger.debug("Copying LICENSE from %s", license_file) 117 shutil.copy(license_file, distInfoFolder) 118 119 with (distInfoFolder / "WHEEL").open("w+", encoding="utf-8") as wl: 120 logger.debug("Writing WHEEL file") 121 wl.writelines([ 122 "Wheel-Version: 1.0\n", 123 "Generator: https://github.com/yoheimuta/protolint/\n", 124 "Root-Is-PureLib: false\n", 125 f"Tag: {tag}\n"] 126 ) 127 128 with (distInfoFolder / "METADATA").open("w+", encoding="utf-8") as ml: 129 logger.debug("Writing METADATA file") 130 ml.writelines([ 131 "Metadata-Version: 2.1\n", 132 f"Name: {package_name}\n", 133 f"Version: {version_id} \n", 134 "Summary: A pluggable linter and fixer to enforce Protocol Buffer style and conventions.\nThis package contains the pre-compiled binaries.\n", 135 "Home-page: https://github.com/yoheimuta/protolint/\n", 136 "Author: yohei yoshimuta\n", 137 "Maintainer: yohei yoshimuta\n", 138 "License: MIT\n", 139 "Project-URL: Official Website, https://github.com/yoheimuta/protolint/\n", 140 "Project-URL: Source Code, https://github.com/yoheimuta/protolint.git\n", 141 "Project-URL: Issue Tracker, https://github.com/yoheimuta/protolint/issues\n", 142 "Classifier: Development Status :: 5 - Production/Stable\n", 143 "Classifier: Environment :: Console\n", 144 "Classifier: Intended Audience :: Developers\n", 145 "Classifier: License :: OSI Approved :: MIT License\n", 146 "Classifier: Natural Language :: English\n", 147 "Classifier: Operating System :: MacOS\n", 148 "Classifier: Operating System :: Microsoft :: Windows\n", 149 "Classifier: Operating System :: POSIX :: Linux\n", 150 "Classifier: Programming Language :: Go\n", 151 "Classifier: Topic :: Software Development :: Pre-processors\n", 152 "Classifier: Topic :: Utilities\n", 153 "Requires-Python: >= 3.0\n", 154 "Description-Content-Type: text/rst\n", 155 "License-File: LICENSE\n", 156 ]) 157 158 ml.writelines(["\n"]) 159 160 with readme_rst.open("r", encoding="utf-8") as readme: 161 ml.writelines(readme.readlines()) 162 163 wheel_content = list(distInfoFolder.glob("**/*")) + list(dataFolder.glob("**/*")) 164 elements_to_relative_paths = {entry: str(entry).lstrip(str(pdir)).lstrip("/").lstrip("\\") for entry in wheel_content if entry.is_file()} 165 with (distInfoFolder / "RECORD").open("w+", encoding="utf-8") as rl: 166 logger.debug("Writing RECORD file") 167 for entry in elements_to_relative_paths.keys(): 168 relPath = elements_to_relative_paths[entry] 169 sha256 = hashlib.sha256(entry.read_bytes()) 170 fs = entry.stat().st_size 171 rl.write(f"{relPath},sha256={sha256.hexdigest()},{str(fs)}\n") 172 173 rl.write(distInfoFolder.name + "/RECORD,,\n") 174 wheel_content.append(distInfoFolder / "RECORD") 175 176 whl_file = wheel / f"{file_name}-{version_id}-{tag}.whl" 177 if whl_file.is_file(): 178 logger.debug("Removing existing wheel file") 179 whl_file.unlink() 180 181 with zipfile.ZipFile(whl_file, "w", compression=zipfile.ZIP_DEFLATED) as whl: 182 logger.info("Creating python wheel %s", whl_file) 183 for content in wheel_content: 184 whl.write( 185 content, 186 content.relative_to(pdir), 187 zipfile.ZIP_DEFLATED, 188 ) 189 190 logger.info("Done")