Skip to content

Commit 0c24d31

Browse files
committed
Add script to manage availability annotations
By running this script, we can expand comments of the form ``` /*System 0.0.1*/ ``` Into either a longer comment that includes the associated OS versions numbers, ``` /*System 0.0.1, @available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *)*/ ``` or, when the `--attribute` option is used, into an actual `@available` attribute: ``` /*System 0.0.1*/@available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *) ``` The script can be run repeatedly to switch between these two forms, as needed.
1 parent 1daa0c9 commit 0c24d31

File tree

1 file changed

+86
-0
lines changed

1 file changed

+86
-0
lines changed

Utilities/expand-availability.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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

Comments
 (0)