1*60517a1eSAndroid Build Coastguard Worker# Copyright 2018 The Bazel Authors. All rights reserved. 2*60517a1eSAndroid Build Coastguard Worker# 3*60517a1eSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 4*60517a1eSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 5*60517a1eSAndroid Build Coastguard Worker# You may obtain a copy of the License at 6*60517a1eSAndroid Build Coastguard Worker# 7*60517a1eSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 8*60517a1eSAndroid Build Coastguard Worker# 9*60517a1eSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 10*60517a1eSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 11*60517a1eSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*60517a1eSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 13*60517a1eSAndroid Build Coastguard Worker# limitations under the License. 14*60517a1eSAndroid Build Coastguard Worker 15*60517a1eSAndroid Build Coastguard Workerfrom __future__ import annotations 16*60517a1eSAndroid Build Coastguard Worker 17*60517a1eSAndroid Build Coastguard Workerimport argparse 18*60517a1eSAndroid Build Coastguard Workerimport base64 19*60517a1eSAndroid Build Coastguard Workerimport hashlib 20*60517a1eSAndroid Build Coastguard Workerimport os 21*60517a1eSAndroid Build Coastguard Workerimport re 22*60517a1eSAndroid Build Coastguard Workerimport stat 23*60517a1eSAndroid Build Coastguard Workerimport sys 24*60517a1eSAndroid Build Coastguard Workerimport zipfile 25*60517a1eSAndroid Build Coastguard Workerfrom pathlib import Path 26*60517a1eSAndroid Build Coastguard Worker 27*60517a1eSAndroid Build Coastguard Worker_ZIP_EPOCH = (1980, 1, 1, 0, 0, 0) 28*60517a1eSAndroid Build Coastguard Worker 29*60517a1eSAndroid Build Coastguard Worker 30*60517a1eSAndroid Build Coastguard Workerdef commonpath(path1, path2): 31*60517a1eSAndroid Build Coastguard Worker ret = [] 32*60517a1eSAndroid Build Coastguard Worker for a, b in zip(path1.split(os.path.sep), path2.split(os.path.sep)): 33*60517a1eSAndroid Build Coastguard Worker if a != b: 34*60517a1eSAndroid Build Coastguard Worker break 35*60517a1eSAndroid Build Coastguard Worker ret.append(a) 36*60517a1eSAndroid Build Coastguard Worker return os.path.sep.join(ret) 37*60517a1eSAndroid Build Coastguard Worker 38*60517a1eSAndroid Build Coastguard Worker 39*60517a1eSAndroid Build Coastguard Workerdef escape_filename_segment(segment): 40*60517a1eSAndroid Build Coastguard Worker """Escapes a filename segment per https://www.python.org/dev/peps/pep-0427/#escaping-and-unicode 41*60517a1eSAndroid Build Coastguard Worker 42*60517a1eSAndroid Build Coastguard Worker This is a legacy function, kept for backwards compatibility, 43*60517a1eSAndroid Build Coastguard Worker and may be removed in the future. See `escape_filename_distribution_name` 44*60517a1eSAndroid Build Coastguard Worker and `normalize_pep440` for the modern alternatives. 45*60517a1eSAndroid Build Coastguard Worker """ 46*60517a1eSAndroid Build Coastguard Worker return re.sub(r"[^\w\d.]+", "_", segment, re.UNICODE) 47*60517a1eSAndroid Build Coastguard Worker 48*60517a1eSAndroid Build Coastguard Worker 49*60517a1eSAndroid Build Coastguard Workerdef normalize_package_name(name): 50*60517a1eSAndroid Build Coastguard Worker """Normalize a package name according to the Python Packaging User Guide. 51*60517a1eSAndroid Build Coastguard Worker 52*60517a1eSAndroid Build Coastguard Worker See https://packaging.python.org/en/latest/specifications/name-normalization/ 53*60517a1eSAndroid Build Coastguard Worker """ 54*60517a1eSAndroid Build Coastguard Worker return re.sub(r"[-_.]+", "-", name).lower() 55*60517a1eSAndroid Build Coastguard Worker 56*60517a1eSAndroid Build Coastguard Worker 57*60517a1eSAndroid Build Coastguard Workerdef escape_filename_distribution_name(name): 58*60517a1eSAndroid Build Coastguard Worker """Escape the distribution name component of a filename. 59*60517a1eSAndroid Build Coastguard Worker 60*60517a1eSAndroid Build Coastguard Worker See https://packaging.python.org/en/latest/specifications/binary-distribution-format/#escaping-and-unicode 61*60517a1eSAndroid Build Coastguard Worker """ 62*60517a1eSAndroid Build Coastguard Worker return normalize_package_name(name).replace("-", "_") 63*60517a1eSAndroid Build Coastguard Worker 64*60517a1eSAndroid Build Coastguard Worker 65*60517a1eSAndroid Build Coastguard Workerdef normalize_pep440(version): 66*60517a1eSAndroid Build Coastguard Worker """Normalize version according to PEP 440, with fallback for placeholders. 67*60517a1eSAndroid Build Coastguard Worker 68*60517a1eSAndroid Build Coastguard Worker If there's a placeholder in braces, such as {BUILD_TIMESTAMP}, 69*60517a1eSAndroid Build Coastguard Worker replace it with 0. Such placeholders can be used with stamping, in 70*60517a1eSAndroid Build Coastguard Worker which case they would have been resolved already by now; if they 71*60517a1eSAndroid Build Coastguard Worker haven't, we're doing an unstamped build, but we still need to 72*60517a1eSAndroid Build Coastguard Worker produce a valid version. If such replacements are made, the 73*60517a1eSAndroid Build Coastguard Worker original version string, sanitized to dot-separated alphanumerics, 74*60517a1eSAndroid Build Coastguard Worker is appended as a local version segment, so you understand what 75*60517a1eSAndroid Build Coastguard Worker placeholder was involved. 76*60517a1eSAndroid Build Coastguard Worker 77*60517a1eSAndroid Build Coastguard Worker If that still doesn't produce a valid version, use version 0 and 78*60517a1eSAndroid Build Coastguard Worker append the original version string, sanitized to dot-separated 79*60517a1eSAndroid Build Coastguard Worker alphanumerics, as a local version segment. 80*60517a1eSAndroid Build Coastguard Worker 81*60517a1eSAndroid Build Coastguard Worker """ 82*60517a1eSAndroid Build Coastguard Worker 83*60517a1eSAndroid Build Coastguard Worker import packaging.version 84*60517a1eSAndroid Build Coastguard Worker 85*60517a1eSAndroid Build Coastguard Worker try: 86*60517a1eSAndroid Build Coastguard Worker return str(packaging.version.Version(version)) 87*60517a1eSAndroid Build Coastguard Worker except packaging.version.InvalidVersion: 88*60517a1eSAndroid Build Coastguard Worker pass 89*60517a1eSAndroid Build Coastguard Worker 90*60517a1eSAndroid Build Coastguard Worker sanitized = re.sub(r"[^a-z0-9]+", ".", version.lower()).strip(".") 91*60517a1eSAndroid Build Coastguard Worker substituted = re.sub(r"\{\w+\}", "0", version) 92*60517a1eSAndroid Build Coastguard Worker delimiter = "." if "+" in substituted else "+" 93*60517a1eSAndroid Build Coastguard Worker try: 94*60517a1eSAndroid Build Coastguard Worker return str(packaging.version.Version(f"{substituted}{delimiter}{sanitized}")) 95*60517a1eSAndroid Build Coastguard Worker except packaging.version.InvalidVersion: 96*60517a1eSAndroid Build Coastguard Worker return str(packaging.version.Version(f"0+{sanitized}")) 97*60517a1eSAndroid Build Coastguard Worker 98*60517a1eSAndroid Build Coastguard Worker 99*60517a1eSAndroid Build Coastguard Workerclass _WhlFile(zipfile.ZipFile): 100*60517a1eSAndroid Build Coastguard Worker def __init__( 101*60517a1eSAndroid Build Coastguard Worker self, 102*60517a1eSAndroid Build Coastguard Worker filename, 103*60517a1eSAndroid Build Coastguard Worker *, 104*60517a1eSAndroid Build Coastguard Worker mode, 105*60517a1eSAndroid Build Coastguard Worker distribution_prefix: str, 106*60517a1eSAndroid Build Coastguard Worker strip_path_prefixes=None, 107*60517a1eSAndroid Build Coastguard Worker compression=zipfile.ZIP_DEFLATED, 108*60517a1eSAndroid Build Coastguard Worker **kwargs, 109*60517a1eSAndroid Build Coastguard Worker ): 110*60517a1eSAndroid Build Coastguard Worker self._distribution_prefix = distribution_prefix 111*60517a1eSAndroid Build Coastguard Worker 112*60517a1eSAndroid Build Coastguard Worker self._strip_path_prefixes = strip_path_prefixes or [] 113*60517a1eSAndroid Build Coastguard Worker # Entries for the RECORD file as (filename, hash, size) tuples. 114*60517a1eSAndroid Build Coastguard Worker self._record = [] 115*60517a1eSAndroid Build Coastguard Worker 116*60517a1eSAndroid Build Coastguard Worker super().__init__(filename, mode=mode, compression=compression, **kwargs) 117*60517a1eSAndroid Build Coastguard Worker 118*60517a1eSAndroid Build Coastguard Worker def distinfo_path(self, basename): 119*60517a1eSAndroid Build Coastguard Worker return f"{self._distribution_prefix}.dist-info/{basename}" 120*60517a1eSAndroid Build Coastguard Worker 121*60517a1eSAndroid Build Coastguard Worker def data_path(self, basename): 122*60517a1eSAndroid Build Coastguard Worker return f"{self._distribution_prefix}.data/{basename}" 123*60517a1eSAndroid Build Coastguard Worker 124*60517a1eSAndroid Build Coastguard Worker def add_file(self, package_filename, real_filename): 125*60517a1eSAndroid Build Coastguard Worker """Add given file to the distribution.""" 126*60517a1eSAndroid Build Coastguard Worker 127*60517a1eSAndroid Build Coastguard Worker def arcname_from(name): 128*60517a1eSAndroid Build Coastguard Worker # Always use unix path separators. 129*60517a1eSAndroid Build Coastguard Worker normalized_arcname = name.replace(os.path.sep, "/") 130*60517a1eSAndroid Build Coastguard Worker # Don't manipulate names filenames in the .distinfo or .data directories. 131*60517a1eSAndroid Build Coastguard Worker if normalized_arcname.startswith(self._distribution_prefix): 132*60517a1eSAndroid Build Coastguard Worker return normalized_arcname 133*60517a1eSAndroid Build Coastguard Worker for prefix in self._strip_path_prefixes: 134*60517a1eSAndroid Build Coastguard Worker if normalized_arcname.startswith(prefix): 135*60517a1eSAndroid Build Coastguard Worker return normalized_arcname[len(prefix) :] 136*60517a1eSAndroid Build Coastguard Worker 137*60517a1eSAndroid Build Coastguard Worker return normalized_arcname 138*60517a1eSAndroid Build Coastguard Worker 139*60517a1eSAndroid Build Coastguard Worker if os.path.isdir(real_filename): 140*60517a1eSAndroid Build Coastguard Worker directory_contents = os.listdir(real_filename) 141*60517a1eSAndroid Build Coastguard Worker for file_ in directory_contents: 142*60517a1eSAndroid Build Coastguard Worker self.add_file( 143*60517a1eSAndroid Build Coastguard Worker "{}/{}".format(package_filename, file_), 144*60517a1eSAndroid Build Coastguard Worker "{}/{}".format(real_filename, file_), 145*60517a1eSAndroid Build Coastguard Worker ) 146*60517a1eSAndroid Build Coastguard Worker return 147*60517a1eSAndroid Build Coastguard Worker 148*60517a1eSAndroid Build Coastguard Worker arcname = arcname_from(package_filename) 149*60517a1eSAndroid Build Coastguard Worker zinfo = self._zipinfo(arcname) 150*60517a1eSAndroid Build Coastguard Worker 151*60517a1eSAndroid Build Coastguard Worker # Write file to the zip archive while computing the hash and length 152*60517a1eSAndroid Build Coastguard Worker hash = hashlib.sha256() 153*60517a1eSAndroid Build Coastguard Worker size = 0 154*60517a1eSAndroid Build Coastguard Worker with open(real_filename, "rb") as fsrc: 155*60517a1eSAndroid Build Coastguard Worker with self.open(zinfo, "w") as fdst: 156*60517a1eSAndroid Build Coastguard Worker while True: 157*60517a1eSAndroid Build Coastguard Worker block = fsrc.read(2**20) 158*60517a1eSAndroid Build Coastguard Worker if not block: 159*60517a1eSAndroid Build Coastguard Worker break 160*60517a1eSAndroid Build Coastguard Worker fdst.write(block) 161*60517a1eSAndroid Build Coastguard Worker hash.update(block) 162*60517a1eSAndroid Build Coastguard Worker size += len(block) 163*60517a1eSAndroid Build Coastguard Worker 164*60517a1eSAndroid Build Coastguard Worker self._add_to_record(arcname, self._serialize_digest(hash), size) 165*60517a1eSAndroid Build Coastguard Worker 166*60517a1eSAndroid Build Coastguard Worker def add_string(self, filename, contents): 167*60517a1eSAndroid Build Coastguard Worker """Add given 'contents' as filename to the distribution.""" 168*60517a1eSAndroid Build Coastguard Worker if isinstance(contents, str): 169*60517a1eSAndroid Build Coastguard Worker contents = contents.encode("utf-8", "surrogateescape") 170*60517a1eSAndroid Build Coastguard Worker zinfo = self._zipinfo(filename) 171*60517a1eSAndroid Build Coastguard Worker self.writestr(zinfo, contents) 172*60517a1eSAndroid Build Coastguard Worker hash = hashlib.sha256() 173*60517a1eSAndroid Build Coastguard Worker hash.update(contents) 174*60517a1eSAndroid Build Coastguard Worker self._add_to_record(filename, self._serialize_digest(hash), len(contents)) 175*60517a1eSAndroid Build Coastguard Worker 176*60517a1eSAndroid Build Coastguard Worker def _serialize_digest(self, hash): 177*60517a1eSAndroid Build Coastguard Worker # https://www.python.org/dev/peps/pep-0376/#record 178*60517a1eSAndroid Build Coastguard Worker # "base64.urlsafe_b64encode(digest) with trailing = removed" 179*60517a1eSAndroid Build Coastguard Worker digest = base64.urlsafe_b64encode(hash.digest()) 180*60517a1eSAndroid Build Coastguard Worker digest = b"sha256=" + digest.rstrip(b"=") 181*60517a1eSAndroid Build Coastguard Worker return digest 182*60517a1eSAndroid Build Coastguard Worker 183*60517a1eSAndroid Build Coastguard Worker def _add_to_record(self, filename, hash, size): 184*60517a1eSAndroid Build Coastguard Worker size = str(size).encode("ascii") 185*60517a1eSAndroid Build Coastguard Worker self._record.append((filename, hash, size)) 186*60517a1eSAndroid Build Coastguard Worker 187*60517a1eSAndroid Build Coastguard Worker def _zipinfo(self, filename): 188*60517a1eSAndroid Build Coastguard Worker """Construct deterministic ZipInfo entry for a file named filename""" 189*60517a1eSAndroid Build Coastguard Worker # Strip leading path separators to mirror ZipInfo.from_file behavior 190*60517a1eSAndroid Build Coastguard Worker separators = os.path.sep 191*60517a1eSAndroid Build Coastguard Worker if os.path.altsep is not None: 192*60517a1eSAndroid Build Coastguard Worker separators += os.path.altsep 193*60517a1eSAndroid Build Coastguard Worker arcname = filename.lstrip(separators) 194*60517a1eSAndroid Build Coastguard Worker 195*60517a1eSAndroid Build Coastguard Worker zinfo = zipfile.ZipInfo(filename=arcname, date_time=_ZIP_EPOCH) 196*60517a1eSAndroid Build Coastguard Worker zinfo.create_system = 3 # ZipInfo entry created on a unix-y system 197*60517a1eSAndroid Build Coastguard Worker # Both pip and installer expect the regular file bit to be set in order for the 198*60517a1eSAndroid Build Coastguard Worker # executable bit to be preserved after extraction 199*60517a1eSAndroid Build Coastguard Worker # https://github.com/pypa/pip/blob/23.3.2/src/pip/_internal/utils/unpacking.py#L96-L100 200*60517a1eSAndroid Build Coastguard Worker # https://github.com/pypa/installer/blob/0.7.0/src/installer/sources.py#L310-L313 201*60517a1eSAndroid Build Coastguard Worker zinfo.external_attr = ( 202*60517a1eSAndroid Build Coastguard Worker stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO | stat.S_IFREG 203*60517a1eSAndroid Build Coastguard Worker ) << 16 # permissions: -rwxrwxrwx 204*60517a1eSAndroid Build Coastguard Worker zinfo.compress_type = self.compression 205*60517a1eSAndroid Build Coastguard Worker return zinfo 206*60517a1eSAndroid Build Coastguard Worker 207*60517a1eSAndroid Build Coastguard Worker def add_recordfile(self): 208*60517a1eSAndroid Build Coastguard Worker """Write RECORD file to the distribution.""" 209*60517a1eSAndroid Build Coastguard Worker record_path = self.distinfo_path("RECORD") 210*60517a1eSAndroid Build Coastguard Worker entries = self._record + [(record_path, b"", b"")] 211*60517a1eSAndroid Build Coastguard Worker contents = b"" 212*60517a1eSAndroid Build Coastguard Worker for filename, digest, size in entries: 213*60517a1eSAndroid Build Coastguard Worker if isinstance(filename, str): 214*60517a1eSAndroid Build Coastguard Worker filename = filename.lstrip("/").encode("utf-8", "surrogateescape") 215*60517a1eSAndroid Build Coastguard Worker contents += b"%s,%s,%s\n" % (filename, digest, size) 216*60517a1eSAndroid Build Coastguard Worker 217*60517a1eSAndroid Build Coastguard Worker self.add_string(record_path, contents) 218*60517a1eSAndroid Build Coastguard Worker return contents 219*60517a1eSAndroid Build Coastguard Worker 220*60517a1eSAndroid Build Coastguard Worker 221*60517a1eSAndroid Build Coastguard Workerclass WheelMaker(object): 222*60517a1eSAndroid Build Coastguard Worker def __init__( 223*60517a1eSAndroid Build Coastguard Worker self, 224*60517a1eSAndroid Build Coastguard Worker name, 225*60517a1eSAndroid Build Coastguard Worker version, 226*60517a1eSAndroid Build Coastguard Worker build_tag, 227*60517a1eSAndroid Build Coastguard Worker python_tag, 228*60517a1eSAndroid Build Coastguard Worker abi, 229*60517a1eSAndroid Build Coastguard Worker platform, 230*60517a1eSAndroid Build Coastguard Worker outfile=None, 231*60517a1eSAndroid Build Coastguard Worker strip_path_prefixes=None, 232*60517a1eSAndroid Build Coastguard Worker ): 233*60517a1eSAndroid Build Coastguard Worker self._name = name 234*60517a1eSAndroid Build Coastguard Worker self._version = normalize_pep440(version) 235*60517a1eSAndroid Build Coastguard Worker self._build_tag = build_tag 236*60517a1eSAndroid Build Coastguard Worker self._python_tag = python_tag 237*60517a1eSAndroid Build Coastguard Worker self._abi = abi 238*60517a1eSAndroid Build Coastguard Worker self._platform = platform 239*60517a1eSAndroid Build Coastguard Worker self._outfile = outfile 240*60517a1eSAndroid Build Coastguard Worker self._strip_path_prefixes = strip_path_prefixes 241*60517a1eSAndroid Build Coastguard Worker self._wheelname_fragment_distribution_name = escape_filename_distribution_name( 242*60517a1eSAndroid Build Coastguard Worker self._name 243*60517a1eSAndroid Build Coastguard Worker ) 244*60517a1eSAndroid Build Coastguard Worker 245*60517a1eSAndroid Build Coastguard Worker self._distribution_prefix = ( 246*60517a1eSAndroid Build Coastguard Worker self._wheelname_fragment_distribution_name + "-" + self._version 247*60517a1eSAndroid Build Coastguard Worker ) 248*60517a1eSAndroid Build Coastguard Worker 249*60517a1eSAndroid Build Coastguard Worker self._whlfile = None 250*60517a1eSAndroid Build Coastguard Worker 251*60517a1eSAndroid Build Coastguard Worker def __enter__(self): 252*60517a1eSAndroid Build Coastguard Worker self._whlfile = _WhlFile( 253*60517a1eSAndroid Build Coastguard Worker self.filename(), 254*60517a1eSAndroid Build Coastguard Worker mode="w", 255*60517a1eSAndroid Build Coastguard Worker distribution_prefix=self._distribution_prefix, 256*60517a1eSAndroid Build Coastguard Worker strip_path_prefixes=self._strip_path_prefixes, 257*60517a1eSAndroid Build Coastguard Worker ) 258*60517a1eSAndroid Build Coastguard Worker return self 259*60517a1eSAndroid Build Coastguard Worker 260*60517a1eSAndroid Build Coastguard Worker def __exit__(self, type, value, traceback): 261*60517a1eSAndroid Build Coastguard Worker self._whlfile.close() 262*60517a1eSAndroid Build Coastguard Worker self._whlfile = None 263*60517a1eSAndroid Build Coastguard Worker 264*60517a1eSAndroid Build Coastguard Worker def wheelname(self) -> str: 265*60517a1eSAndroid Build Coastguard Worker components = [ 266*60517a1eSAndroid Build Coastguard Worker self._wheelname_fragment_distribution_name, 267*60517a1eSAndroid Build Coastguard Worker self._version, 268*60517a1eSAndroid Build Coastguard Worker ] 269*60517a1eSAndroid Build Coastguard Worker if self._build_tag: 270*60517a1eSAndroid Build Coastguard Worker components.append(self._build_tag) 271*60517a1eSAndroid Build Coastguard Worker components += [self._python_tag, self._abi, self._platform] 272*60517a1eSAndroid Build Coastguard Worker return "-".join(components) + ".whl" 273*60517a1eSAndroid Build Coastguard Worker 274*60517a1eSAndroid Build Coastguard Worker def filename(self) -> str: 275*60517a1eSAndroid Build Coastguard Worker if self._outfile: 276*60517a1eSAndroid Build Coastguard Worker return self._outfile 277*60517a1eSAndroid Build Coastguard Worker return self.wheelname() 278*60517a1eSAndroid Build Coastguard Worker 279*60517a1eSAndroid Build Coastguard Worker def disttags(self): 280*60517a1eSAndroid Build Coastguard Worker return ["-".join([self._python_tag, self._abi, self._platform])] 281*60517a1eSAndroid Build Coastguard Worker 282*60517a1eSAndroid Build Coastguard Worker def distinfo_path(self, basename): 283*60517a1eSAndroid Build Coastguard Worker return self._whlfile.distinfo_path(basename) 284*60517a1eSAndroid Build Coastguard Worker 285*60517a1eSAndroid Build Coastguard Worker def data_path(self, basename): 286*60517a1eSAndroid Build Coastguard Worker return self._whlfile.data_path(basename) 287*60517a1eSAndroid Build Coastguard Worker 288*60517a1eSAndroid Build Coastguard Worker def add_file(self, package_filename, real_filename): 289*60517a1eSAndroid Build Coastguard Worker """Add given file to the distribution.""" 290*60517a1eSAndroid Build Coastguard Worker self._whlfile.add_file(package_filename, real_filename) 291*60517a1eSAndroid Build Coastguard Worker 292*60517a1eSAndroid Build Coastguard Worker def add_wheelfile(self): 293*60517a1eSAndroid Build Coastguard Worker """Write WHEEL file to the distribution""" 294*60517a1eSAndroid Build Coastguard Worker # TODO(pstradomski): Support non-purelib wheels. 295*60517a1eSAndroid Build Coastguard Worker wheel_contents = """\ 296*60517a1eSAndroid Build Coastguard WorkerWheel-Version: 1.0 297*60517a1eSAndroid Build Coastguard WorkerGenerator: bazel-wheelmaker 1.0 298*60517a1eSAndroid Build Coastguard WorkerRoot-Is-Purelib: {} 299*60517a1eSAndroid Build Coastguard Worker""".format( 300*60517a1eSAndroid Build Coastguard Worker "true" if self._platform == "any" else "false" 301*60517a1eSAndroid Build Coastguard Worker ) 302*60517a1eSAndroid Build Coastguard Worker for tag in self.disttags(): 303*60517a1eSAndroid Build Coastguard Worker wheel_contents += "Tag: %s\n" % tag 304*60517a1eSAndroid Build Coastguard Worker self._whlfile.add_string(self.distinfo_path("WHEEL"), wheel_contents) 305*60517a1eSAndroid Build Coastguard Worker 306*60517a1eSAndroid Build Coastguard Worker def add_metadata(self, metadata, name, description): 307*60517a1eSAndroid Build Coastguard Worker """Write METADATA file to the distribution.""" 308*60517a1eSAndroid Build Coastguard Worker # https://www.python.org/dev/peps/pep-0566/ 309*60517a1eSAndroid Build Coastguard Worker # https://packaging.python.org/specifications/core-metadata/ 310*60517a1eSAndroid Build Coastguard Worker metadata = re.sub("^Name: .*$", "Name: %s" % name, metadata, flags=re.MULTILINE) 311*60517a1eSAndroid Build Coastguard Worker metadata += "Version: %s\n\n" % self._version 312*60517a1eSAndroid Build Coastguard Worker # setuptools seems to insert UNKNOWN as description when none is 313*60517a1eSAndroid Build Coastguard Worker # provided. 314*60517a1eSAndroid Build Coastguard Worker metadata += description if description else "UNKNOWN" 315*60517a1eSAndroid Build Coastguard Worker metadata += "\n" 316*60517a1eSAndroid Build Coastguard Worker self._whlfile.add_string(self.distinfo_path("METADATA"), metadata) 317*60517a1eSAndroid Build Coastguard Worker 318*60517a1eSAndroid Build Coastguard Worker def add_recordfile(self): 319*60517a1eSAndroid Build Coastguard Worker """Write RECORD file to the distribution.""" 320*60517a1eSAndroid Build Coastguard Worker self._whlfile.add_recordfile() 321*60517a1eSAndroid Build Coastguard Worker 322*60517a1eSAndroid Build Coastguard Worker 323*60517a1eSAndroid Build Coastguard Workerdef get_files_to_package(input_files): 324*60517a1eSAndroid Build Coastguard Worker """Find files to be added to the distribution. 325*60517a1eSAndroid Build Coastguard Worker 326*60517a1eSAndroid Build Coastguard Worker input_files: list of pairs (package_path, real_path) 327*60517a1eSAndroid Build Coastguard Worker """ 328*60517a1eSAndroid Build Coastguard Worker files = {} 329*60517a1eSAndroid Build Coastguard Worker for package_path, real_path in input_files: 330*60517a1eSAndroid Build Coastguard Worker files[package_path] = real_path 331*60517a1eSAndroid Build Coastguard Worker return files 332*60517a1eSAndroid Build Coastguard Worker 333*60517a1eSAndroid Build Coastguard Worker 334*60517a1eSAndroid Build Coastguard Workerdef resolve_argument_stamp( 335*60517a1eSAndroid Build Coastguard Worker argument: str, volatile_status_stamp: Path, stable_status_stamp: Path 336*60517a1eSAndroid Build Coastguard Worker) -> str: 337*60517a1eSAndroid Build Coastguard Worker """Resolve workspace status stamps format strings found in the argument string 338*60517a1eSAndroid Build Coastguard Worker 339*60517a1eSAndroid Build Coastguard Worker Args: 340*60517a1eSAndroid Build Coastguard Worker argument (str): The raw argument represenation for the wheel (may include stamp variables) 341*60517a1eSAndroid Build Coastguard Worker volatile_status_stamp (Path): The path to a volatile workspace status file 342*60517a1eSAndroid Build Coastguard Worker stable_status_stamp (Path): The path to a stable workspace status file 343*60517a1eSAndroid Build Coastguard Worker 344*60517a1eSAndroid Build Coastguard Worker Returns: 345*60517a1eSAndroid Build Coastguard Worker str: A resolved argument string 346*60517a1eSAndroid Build Coastguard Worker """ 347*60517a1eSAndroid Build Coastguard Worker lines = ( 348*60517a1eSAndroid Build Coastguard Worker volatile_status_stamp.read_text().splitlines() 349*60517a1eSAndroid Build Coastguard Worker + stable_status_stamp.read_text().splitlines() 350*60517a1eSAndroid Build Coastguard Worker ) 351*60517a1eSAndroid Build Coastguard Worker for line in lines: 352*60517a1eSAndroid Build Coastguard Worker if not line: 353*60517a1eSAndroid Build Coastguard Worker continue 354*60517a1eSAndroid Build Coastguard Worker key, value = line.split(" ", maxsplit=1) 355*60517a1eSAndroid Build Coastguard Worker stamp = "{" + key + "}" 356*60517a1eSAndroid Build Coastguard Worker argument = argument.replace(stamp, value) 357*60517a1eSAndroid Build Coastguard Worker 358*60517a1eSAndroid Build Coastguard Worker return argument 359*60517a1eSAndroid Build Coastguard Worker 360*60517a1eSAndroid Build Coastguard Worker 361*60517a1eSAndroid Build Coastguard Workerdef parse_args() -> argparse.Namespace: 362*60517a1eSAndroid Build Coastguard Worker parser = argparse.ArgumentParser(description="Builds a python wheel") 363*60517a1eSAndroid Build Coastguard Worker metadata_group = parser.add_argument_group("Wheel name, version and platform") 364*60517a1eSAndroid Build Coastguard Worker metadata_group.add_argument( 365*60517a1eSAndroid Build Coastguard Worker "--name", required=True, type=str, help="Name of the distribution" 366*60517a1eSAndroid Build Coastguard Worker ) 367*60517a1eSAndroid Build Coastguard Worker metadata_group.add_argument( 368*60517a1eSAndroid Build Coastguard Worker "--version", required=True, type=str, help="Version of the distribution" 369*60517a1eSAndroid Build Coastguard Worker ) 370*60517a1eSAndroid Build Coastguard Worker metadata_group.add_argument( 371*60517a1eSAndroid Build Coastguard Worker "--build_tag", 372*60517a1eSAndroid Build Coastguard Worker type=str, 373*60517a1eSAndroid Build Coastguard Worker default="", 374*60517a1eSAndroid Build Coastguard Worker help="Optional build tag for the distribution", 375*60517a1eSAndroid Build Coastguard Worker ) 376*60517a1eSAndroid Build Coastguard Worker metadata_group.add_argument( 377*60517a1eSAndroid Build Coastguard Worker "--python_tag", 378*60517a1eSAndroid Build Coastguard Worker type=str, 379*60517a1eSAndroid Build Coastguard Worker default="py3", 380*60517a1eSAndroid Build Coastguard Worker help="Python version, e.g. 'py2' or 'py3'", 381*60517a1eSAndroid Build Coastguard Worker ) 382*60517a1eSAndroid Build Coastguard Worker metadata_group.add_argument("--abi", type=str, default="none") 383*60517a1eSAndroid Build Coastguard Worker metadata_group.add_argument( 384*60517a1eSAndroid Build Coastguard Worker "--platform", type=str, default="any", help="Target platform. " 385*60517a1eSAndroid Build Coastguard Worker ) 386*60517a1eSAndroid Build Coastguard Worker 387*60517a1eSAndroid Build Coastguard Worker output_group = parser.add_argument_group("Output file location") 388*60517a1eSAndroid Build Coastguard Worker output_group.add_argument( 389*60517a1eSAndroid Build Coastguard Worker "--out", type=str, default=None, help="Override name of ouptut file" 390*60517a1eSAndroid Build Coastguard Worker ) 391*60517a1eSAndroid Build Coastguard Worker output_group.add_argument( 392*60517a1eSAndroid Build Coastguard Worker "--name_file", 393*60517a1eSAndroid Build Coastguard Worker type=Path, 394*60517a1eSAndroid Build Coastguard Worker help="A file where the canonical name of the " "wheel will be written", 395*60517a1eSAndroid Build Coastguard Worker ) 396*60517a1eSAndroid Build Coastguard Worker 397*60517a1eSAndroid Build Coastguard Worker output_group.add_argument( 398*60517a1eSAndroid Build Coastguard Worker "--strip_path_prefix", 399*60517a1eSAndroid Build Coastguard Worker type=str, 400*60517a1eSAndroid Build Coastguard Worker action="append", 401*60517a1eSAndroid Build Coastguard Worker default=[], 402*60517a1eSAndroid Build Coastguard Worker help="Path prefix to be stripped from input package files' path. " 403*60517a1eSAndroid Build Coastguard Worker "Can be supplied multiple times. Evaluated in order.", 404*60517a1eSAndroid Build Coastguard Worker ) 405*60517a1eSAndroid Build Coastguard Worker 406*60517a1eSAndroid Build Coastguard Worker wheel_group = parser.add_argument_group("Wheel metadata") 407*60517a1eSAndroid Build Coastguard Worker wheel_group.add_argument( 408*60517a1eSAndroid Build Coastguard Worker "--metadata_file", 409*60517a1eSAndroid Build Coastguard Worker type=Path, 410*60517a1eSAndroid Build Coastguard Worker help="Contents of the METADATA file (before appending contents of " 411*60517a1eSAndroid Build Coastguard Worker "--description_file)", 412*60517a1eSAndroid Build Coastguard Worker ) 413*60517a1eSAndroid Build Coastguard Worker wheel_group.add_argument( 414*60517a1eSAndroid Build Coastguard Worker "--description_file", help="Path to the file with package description" 415*60517a1eSAndroid Build Coastguard Worker ) 416*60517a1eSAndroid Build Coastguard Worker wheel_group.add_argument( 417*60517a1eSAndroid Build Coastguard Worker "--description_content_type", help="Content type of the package description" 418*60517a1eSAndroid Build Coastguard Worker ) 419*60517a1eSAndroid Build Coastguard Worker wheel_group.add_argument( 420*60517a1eSAndroid Build Coastguard Worker "--entry_points_file", 421*60517a1eSAndroid Build Coastguard Worker help="Path to a correctly-formatted entry_points.txt file", 422*60517a1eSAndroid Build Coastguard Worker ) 423*60517a1eSAndroid Build Coastguard Worker 424*60517a1eSAndroid Build Coastguard Worker contents_group = parser.add_argument_group("Wheel contents") 425*60517a1eSAndroid Build Coastguard Worker contents_group.add_argument( 426*60517a1eSAndroid Build Coastguard Worker "--input_file", 427*60517a1eSAndroid Build Coastguard Worker action="append", 428*60517a1eSAndroid Build Coastguard Worker help="'package_path;real_path' pairs listing " 429*60517a1eSAndroid Build Coastguard Worker "files to be included in the wheel. " 430*60517a1eSAndroid Build Coastguard Worker "Can be supplied multiple times.", 431*60517a1eSAndroid Build Coastguard Worker ) 432*60517a1eSAndroid Build Coastguard Worker contents_group.add_argument( 433*60517a1eSAndroid Build Coastguard Worker "--input_file_list", 434*60517a1eSAndroid Build Coastguard Worker action="append", 435*60517a1eSAndroid Build Coastguard Worker help="A file that has all the input files defined as a list to avoid " 436*60517a1eSAndroid Build Coastguard Worker "the long command", 437*60517a1eSAndroid Build Coastguard Worker ) 438*60517a1eSAndroid Build Coastguard Worker contents_group.add_argument( 439*60517a1eSAndroid Build Coastguard Worker "--extra_distinfo_file", 440*60517a1eSAndroid Build Coastguard Worker action="append", 441*60517a1eSAndroid Build Coastguard Worker help="'filename;real_path' pairs listing extra files to include in" 442*60517a1eSAndroid Build Coastguard Worker "dist-info directory. Can be supplied multiple times.", 443*60517a1eSAndroid Build Coastguard Worker ) 444*60517a1eSAndroid Build Coastguard Worker contents_group.add_argument( 445*60517a1eSAndroid Build Coastguard Worker "--data_files", 446*60517a1eSAndroid Build Coastguard Worker action="append", 447*60517a1eSAndroid Build Coastguard Worker help="'filename;real_path' pairs listing data files to include in" 448*60517a1eSAndroid Build Coastguard Worker "data directory. Can be supplied multiple times.", 449*60517a1eSAndroid Build Coastguard Worker ) 450*60517a1eSAndroid Build Coastguard Worker 451*60517a1eSAndroid Build Coastguard Worker build_group = parser.add_argument_group("Building requirements") 452*60517a1eSAndroid Build Coastguard Worker build_group.add_argument( 453*60517a1eSAndroid Build Coastguard Worker "--volatile_status_file", 454*60517a1eSAndroid Build Coastguard Worker type=Path, 455*60517a1eSAndroid Build Coastguard Worker help="Pass in the stamp info file for stamping", 456*60517a1eSAndroid Build Coastguard Worker ) 457*60517a1eSAndroid Build Coastguard Worker build_group.add_argument( 458*60517a1eSAndroid Build Coastguard Worker "--stable_status_file", 459*60517a1eSAndroid Build Coastguard Worker type=Path, 460*60517a1eSAndroid Build Coastguard Worker help="Pass in the stamp info file for stamping", 461*60517a1eSAndroid Build Coastguard Worker ) 462*60517a1eSAndroid Build Coastguard Worker 463*60517a1eSAndroid Build Coastguard Worker return parser.parse_args(sys.argv[1:]) 464*60517a1eSAndroid Build Coastguard Worker 465*60517a1eSAndroid Build Coastguard Worker 466*60517a1eSAndroid Build Coastguard Workerdef _parse_file_pairs(content: List[str]) -> List[List[str]]: 467*60517a1eSAndroid Build Coastguard Worker """ 468*60517a1eSAndroid Build Coastguard Worker Parse ; delimited lists of files into a 2D list. 469*60517a1eSAndroid Build Coastguard Worker """ 470*60517a1eSAndroid Build Coastguard Worker return [i.split(";", maxsplit=1) for i in content or []] 471*60517a1eSAndroid Build Coastguard Worker 472*60517a1eSAndroid Build Coastguard Worker 473*60517a1eSAndroid Build Coastguard Workerdef main() -> None: 474*60517a1eSAndroid Build Coastguard Worker arguments = parse_args() 475*60517a1eSAndroid Build Coastguard Worker 476*60517a1eSAndroid Build Coastguard Worker input_files = _parse_file_pairs(arguments.input_file) 477*60517a1eSAndroid Build Coastguard Worker extra_distinfo_file = _parse_file_pairs(arguments.extra_distinfo_file) 478*60517a1eSAndroid Build Coastguard Worker data_files = _parse_file_pairs(arguments.data_files) 479*60517a1eSAndroid Build Coastguard Worker 480*60517a1eSAndroid Build Coastguard Worker for input_file in arguments.input_file_list: 481*60517a1eSAndroid Build Coastguard Worker with open(input_file) as _file: 482*60517a1eSAndroid Build Coastguard Worker input_file_list = _file.read().splitlines() 483*60517a1eSAndroid Build Coastguard Worker for _input_file in input_file_list: 484*60517a1eSAndroid Build Coastguard Worker input_files.append(_input_file.split(";")) 485*60517a1eSAndroid Build Coastguard Worker 486*60517a1eSAndroid Build Coastguard Worker all_files = get_files_to_package(input_files) 487*60517a1eSAndroid Build Coastguard Worker # Sort the files for reproducible order in the archive. 488*60517a1eSAndroid Build Coastguard Worker all_files = sorted(all_files.items()) 489*60517a1eSAndroid Build Coastguard Worker 490*60517a1eSAndroid Build Coastguard Worker strip_prefixes = [p for p in arguments.strip_path_prefix] 491*60517a1eSAndroid Build Coastguard Worker 492*60517a1eSAndroid Build Coastguard Worker if arguments.volatile_status_file and arguments.stable_status_file: 493*60517a1eSAndroid Build Coastguard Worker name = resolve_argument_stamp( 494*60517a1eSAndroid Build Coastguard Worker arguments.name, 495*60517a1eSAndroid Build Coastguard Worker arguments.volatile_status_file, 496*60517a1eSAndroid Build Coastguard Worker arguments.stable_status_file, 497*60517a1eSAndroid Build Coastguard Worker ) 498*60517a1eSAndroid Build Coastguard Worker else: 499*60517a1eSAndroid Build Coastguard Worker name = arguments.name 500*60517a1eSAndroid Build Coastguard Worker 501*60517a1eSAndroid Build Coastguard Worker if arguments.volatile_status_file and arguments.stable_status_file: 502*60517a1eSAndroid Build Coastguard Worker version = resolve_argument_stamp( 503*60517a1eSAndroid Build Coastguard Worker arguments.version, 504*60517a1eSAndroid Build Coastguard Worker arguments.volatile_status_file, 505*60517a1eSAndroid Build Coastguard Worker arguments.stable_status_file, 506*60517a1eSAndroid Build Coastguard Worker ) 507*60517a1eSAndroid Build Coastguard Worker else: 508*60517a1eSAndroid Build Coastguard Worker version = arguments.version 509*60517a1eSAndroid Build Coastguard Worker 510*60517a1eSAndroid Build Coastguard Worker with WheelMaker( 511*60517a1eSAndroid Build Coastguard Worker name=name, 512*60517a1eSAndroid Build Coastguard Worker version=version, 513*60517a1eSAndroid Build Coastguard Worker build_tag=arguments.build_tag, 514*60517a1eSAndroid Build Coastguard Worker python_tag=arguments.python_tag, 515*60517a1eSAndroid Build Coastguard Worker abi=arguments.abi, 516*60517a1eSAndroid Build Coastguard Worker platform=arguments.platform, 517*60517a1eSAndroid Build Coastguard Worker outfile=arguments.out, 518*60517a1eSAndroid Build Coastguard Worker strip_path_prefixes=strip_prefixes, 519*60517a1eSAndroid Build Coastguard Worker ) as maker: 520*60517a1eSAndroid Build Coastguard Worker for package_filename, real_filename in all_files: 521*60517a1eSAndroid Build Coastguard Worker maker.add_file(package_filename, real_filename) 522*60517a1eSAndroid Build Coastguard Worker maker.add_wheelfile() 523*60517a1eSAndroid Build Coastguard Worker 524*60517a1eSAndroid Build Coastguard Worker description = None 525*60517a1eSAndroid Build Coastguard Worker if arguments.description_file: 526*60517a1eSAndroid Build Coastguard Worker with open( 527*60517a1eSAndroid Build Coastguard Worker arguments.description_file, "rt", encoding="utf-8" 528*60517a1eSAndroid Build Coastguard Worker ) as description_file: 529*60517a1eSAndroid Build Coastguard Worker description = description_file.read() 530*60517a1eSAndroid Build Coastguard Worker 531*60517a1eSAndroid Build Coastguard Worker metadata = arguments.metadata_file.read_text(encoding="utf-8") 532*60517a1eSAndroid Build Coastguard Worker 533*60517a1eSAndroid Build Coastguard Worker # This is not imported at the top of the file due to the reliance 534*60517a1eSAndroid Build Coastguard Worker # on this file in the `whl_library` repository rule which does not 535*60517a1eSAndroid Build Coastguard Worker # provide `packaging` but does import symbols defined here. 536*60517a1eSAndroid Build Coastguard Worker from packaging.requirements import Requirement 537*60517a1eSAndroid Build Coastguard Worker 538*60517a1eSAndroid Build Coastguard Worker # Search for any `Requires-Dist` entries that refer to other files and 539*60517a1eSAndroid Build Coastguard Worker # expand them. 540*60517a1eSAndroid Build Coastguard Worker 541*60517a1eSAndroid Build Coastguard Worker def get_new_requirement_line(reqs_text, extra): 542*60517a1eSAndroid Build Coastguard Worker req = Requirement(reqs_text.strip()) 543*60517a1eSAndroid Build Coastguard Worker if req.marker: 544*60517a1eSAndroid Build Coastguard Worker if extra: 545*60517a1eSAndroid Build Coastguard Worker return f"Requires-Dist: {req.name}{req.specifier}; ({req.marker}) and {extra}" 546*60517a1eSAndroid Build Coastguard Worker else: 547*60517a1eSAndroid Build Coastguard Worker return f"Requires-Dist: {req.name}{req.specifier}; {req.marker}" 548*60517a1eSAndroid Build Coastguard Worker else: 549*60517a1eSAndroid Build Coastguard Worker return f"Requires-Dist: {req.name}{req.specifier}; {extra}".strip(" ;") 550*60517a1eSAndroid Build Coastguard Worker 551*60517a1eSAndroid Build Coastguard Worker for meta_line in metadata.splitlines(): 552*60517a1eSAndroid Build Coastguard Worker if not meta_line.startswith("Requires-Dist: "): 553*60517a1eSAndroid Build Coastguard Worker continue 554*60517a1eSAndroid Build Coastguard Worker 555*60517a1eSAndroid Build Coastguard Worker if not meta_line[len("Requires-Dist: ") :].startswith("@"): 556*60517a1eSAndroid Build Coastguard Worker # This is a normal requirement. 557*60517a1eSAndroid Build Coastguard Worker package, _, extra = meta_line[len("Requires-Dist: ") :].rpartition(";") 558*60517a1eSAndroid Build Coastguard Worker if not package: 559*60517a1eSAndroid Build Coastguard Worker # This is when the package requirement does not have markers. 560*60517a1eSAndroid Build Coastguard Worker continue 561*60517a1eSAndroid Build Coastguard Worker extra = extra.strip() 562*60517a1eSAndroid Build Coastguard Worker metadata = metadata.replace( 563*60517a1eSAndroid Build Coastguard Worker meta_line, get_new_requirement_line(package, extra) 564*60517a1eSAndroid Build Coastguard Worker ) 565*60517a1eSAndroid Build Coastguard Worker continue 566*60517a1eSAndroid Build Coastguard Worker 567*60517a1eSAndroid Build Coastguard Worker # This is a requirement that refers to a file. 568*60517a1eSAndroid Build Coastguard Worker file, _, extra = meta_line[len("Requires-Dist: @") :].partition(";") 569*60517a1eSAndroid Build Coastguard Worker extra = extra.strip() 570*60517a1eSAndroid Build Coastguard Worker 571*60517a1eSAndroid Build Coastguard Worker reqs = [] 572*60517a1eSAndroid Build Coastguard Worker for reqs_line in Path(file).read_text(encoding="utf-8").splitlines(): 573*60517a1eSAndroid Build Coastguard Worker reqs_text = reqs_line.strip() 574*60517a1eSAndroid Build Coastguard Worker if not reqs_text or reqs_text.startswith(("#", "-")): 575*60517a1eSAndroid Build Coastguard Worker continue 576*60517a1eSAndroid Build Coastguard Worker 577*60517a1eSAndroid Build Coastguard Worker # Strip any comments 578*60517a1eSAndroid Build Coastguard Worker reqs_text, _, _ = reqs_text.partition("#") 579*60517a1eSAndroid Build Coastguard Worker 580*60517a1eSAndroid Build Coastguard Worker reqs.append(get_new_requirement_line(reqs_text, extra)) 581*60517a1eSAndroid Build Coastguard Worker 582*60517a1eSAndroid Build Coastguard Worker metadata = metadata.replace(meta_line, "\n".join(reqs)) 583*60517a1eSAndroid Build Coastguard Worker 584*60517a1eSAndroid Build Coastguard Worker maker.add_metadata( 585*60517a1eSAndroid Build Coastguard Worker metadata=metadata, 586*60517a1eSAndroid Build Coastguard Worker name=name, 587*60517a1eSAndroid Build Coastguard Worker description=description, 588*60517a1eSAndroid Build Coastguard Worker ) 589*60517a1eSAndroid Build Coastguard Worker 590*60517a1eSAndroid Build Coastguard Worker if arguments.entry_points_file: 591*60517a1eSAndroid Build Coastguard Worker maker.add_file( 592*60517a1eSAndroid Build Coastguard Worker maker.distinfo_path("entry_points.txt"), arguments.entry_points_file 593*60517a1eSAndroid Build Coastguard Worker ) 594*60517a1eSAndroid Build Coastguard Worker 595*60517a1eSAndroid Build Coastguard Worker # Sort the files for reproducible order in the archive. 596*60517a1eSAndroid Build Coastguard Worker for filename, real_path in sorted(data_files): 597*60517a1eSAndroid Build Coastguard Worker maker.add_file(maker.data_path(filename), real_path) 598*60517a1eSAndroid Build Coastguard Worker for filename, real_path in sorted(extra_distinfo_file): 599*60517a1eSAndroid Build Coastguard Worker maker.add_file(maker.distinfo_path(filename), real_path) 600*60517a1eSAndroid Build Coastguard Worker 601*60517a1eSAndroid Build Coastguard Worker maker.add_recordfile() 602*60517a1eSAndroid Build Coastguard Worker 603*60517a1eSAndroid Build Coastguard Worker # Since stamping may otherwise change the target name of the 604*60517a1eSAndroid Build Coastguard Worker # wheel, the canonical name (with stamps resolved) is written 605*60517a1eSAndroid Build Coastguard Worker # to a file so consumers of the wheel can easily determine 606*60517a1eSAndroid Build Coastguard Worker # the correct name. 607*60517a1eSAndroid Build Coastguard Worker arguments.name_file.write_text(maker.wheelname()) 608*60517a1eSAndroid Build Coastguard Worker 609*60517a1eSAndroid Build Coastguard Worker 610*60517a1eSAndroid Build Coastguard Workerif __name__ == "__main__": 611*60517a1eSAndroid Build Coastguard Worker main() 612