|
| 1 | +#!/usr/bin/env python3 |
| 2 | + |
| 3 | +# This script uses the file `availability-macros.def` to automatically |
| 4 | +# add/remove `@available` attributes to declarations in Swift sources |
| 5 | +# in this package. |
| 6 | +# |
| 7 | +# In order for this to work, ABI-impacting declarations need to be annotated |
| 8 | +# with special comments in the following format: |
| 9 | +# |
| 10 | +# /*System 0.0.2*/ |
| 11 | +# public func greeting() -> String { |
| 12 | +# "Hello" |
| 13 | +# } |
| 14 | +# |
| 15 | +# The script adds full availability incantations to these comments. It can run |
| 16 | +# in one of two modes: |
| 17 | +# |
| 18 | +# By default, `expand-availability.py` expands availability macros within the |
| 19 | +# comments. This is useful during package development to cross-reference |
| 20 | +# availability across `SystemPackage` and the ABI-stable `System` module that |
| 21 | +# ships in Apple's OS releases: |
| 22 | +# |
| 23 | +# /*System 0.0.2, @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *)*/ |
| 24 | +# public func greeting() -> String { |
| 25 | +# "Hello" |
| 26 | +# } |
| 27 | +# |
| 28 | +# `expand-availability.py --attributes` adds actual availability attributes. |
| 29 | +# This is used by maintainers to build ABI stable releases of System on Apple's |
| 30 | +# platforms: |
| 31 | +# |
| 32 | +# /*System 0.0.2*/@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) |
| 33 | +# public func greeting() -> String { |
| 34 | +# "Hello" |
| 35 | +# } |
| 36 | +# |
| 37 | +# The script recognizes these attributes and updates/removes them on each run, |
| 38 | +# so you can run the script to enable/disable attributes without worrying about |
| 39 | +# duplicate attributes. |
| 40 | + |
| 41 | +import os |
| 42 | +import os.path |
| 43 | +import fileinput |
| 44 | +import re |
| 45 | +import sys |
| 46 | +import argparse |
| 47 | + |
| 48 | +versions = { |
| 49 | + "System 0.0.1": "macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0", |
| 50 | + "System 0.0.2": "macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0", |
| 51 | + "System 1.1.0": "macOS 9999, iOS 9999, watchOS 9999, tvOS 9999", |
| 52 | +} |
| 53 | + |
| 54 | +parser = argparse.ArgumentParser(description="Expand availability macros.") |
| 55 | +parser.add_argument("--attributes", help="Add @available attributes", |
| 56 | + action="store_true") |
| 57 | +args = parser.parse_args() |
| 58 | + |
| 59 | +def swift_sources_in(path): |
| 60 | + result = [] |
| 61 | + for (dir, _, files) in os.walk(path): |
| 62 | + for file in files: |
| 63 | + extension = os.path.splitext(file)[1] |
| 64 | + if extension == ".swift": |
| 65 | + result.append(os.path.join(dir, file)) |
| 66 | + return result |
| 67 | + |
| 68 | +macro_pattern = re.compile( |
| 69 | + r"/\*(System [^ *]+)(, @available\([^)]*\))?\*/(@available\([^)]*\))?") |
| 70 | + |
| 71 | +sources = swift_sources_in("Sources") + swift_sources_in("Tests") |
| 72 | +for line in fileinput.input(files=sources, inplace=True): |
| 73 | + match = re.search(macro_pattern, line) |
| 74 | + if match: |
| 75 | + system_version = match.group(1) |
| 76 | + expansion = versions[system_version] |
| 77 | + if expansion is None: |
| 78 | + raise ValueError("{0}:{1}: error: Unknown System version '{0}'" |
| 79 | + .format(fileinput.filename(), fileinput.lineno(), |
| 80 | + system_version)) |
| 81 | + if args.attributes: |
| 82 | + replacement = "/*{0}*/@available({1}, *)".format(system_version, expansion) |
| 83 | + else: |
| 84 | + replacement = "/*{0}, @available({1}, *)*/".format(system_version, expansion) |
| 85 | + line = line[:match.start()] + replacement + line[match.end():] |
| 86 | + print(line, end="") |
0 commit comments