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")