• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (C) 2023 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15# An API level, can be a finalized (numbered) API, a preview (codenamed) API, or
16# the future API level (10000). Can be parsed from a string with
17# parse_api_level_with_version.
18
19load("@bazel_skylib//lib:dicts.bzl", "dicts")
20load("@soong_injection//api_levels:platform_versions.bzl", "platform_versions")
21load(":api_constants.bzl", "api_levels_released_versions")
22
23_NONE_API_LEVEL_INT = -1
24_PREVIEW_API_LEVEL_BASE = 9000  # Base constant for preview API levels.
25_FUTURE_API_LEVEL_INT = 10000  # API Level associated with an arbitrary future release
26
27# Dict of unfinalized codenames to a placeholder preview API int.
28def _preview_codenames_to_ints(platform_sdk_variables):
29    return {
30        codename: _PREVIEW_API_LEVEL_BASE + i
31        for i, codename in enumerate(platform_sdk_variables.platform_version_active_codenames)
32    }
33
34# Returns true if a string or int version is in preview (not finalized).
35def _is_preview(version, platform_sdk_variables):
36    preview_codenames_to_ints = _preview_codenames_to_ints(platform_sdk_variables)
37    if type(version) == "string" and version.isdigit():
38        # normalize int types internally
39        version = int(version)
40
41    # Future / current / none is considered as a preview.
42    if version in ("current", "(no version)", _FUTURE_API_LEVEL_INT, _NONE_API_LEVEL_INT):
43        return True
44
45    # api can be either the codename or the int level (9000+)
46    return version in preview_codenames_to_ints or version in preview_codenames_to_ints.values()
47
48# Return 10000 for unfinalized versions, otherwise return unchanged.
49def _final_or_future(version, platform_sdk_variables):
50    if _is_preview(version = version, platform_sdk_variables = platform_sdk_variables):
51        return _FUTURE_API_LEVEL_INT
52    else:
53        return version
54
55def _api_levels_with_previews(platform_sdk_variables):
56    return dicts.add(
57        api_levels_released_versions,
58        _preview_codenames_to_ints(platform_sdk_variables),
59    )
60
61# @unused
62def _api_levels_with_final_codenames(platform_sdk_variables):
63    if platform_sdk_variables.platform_sdk_final and platform_sdk_variables.platform_sdk_version:
64        return api_levels_released_versions
65    return dicts.add(
66        api_levels_released_versions,
67        {"current": _final_or_future(
68            version = platform_sdk_variables.platform_sdk_version,
69            platform_sdk_variables = platform_sdk_variables,
70        )},
71    )
72
73# parse_api_level_from_version is a Starlark implementation of ApiLevelFromUser
74# at https://cs.android.com/android/platform/superproject/+/master:build/soong/android/api_levels.go;l=221-250;drc=5095a6c4b484f34d5c4f55a855d6174e00fb7f5e
75def _parse_api_level_from_version(version, platform_sdk_variables):
76    """converts the given string `version` to an api level
77
78    Args:
79        version: must be non-empty. Inputs that are not "current", known
80        previews, finalized codenames, or convertible to an integer will return
81        an error.
82
83    Returns: The api level as an int.
84    """
85    if version == "":
86        fail("API level string must be non-empty")
87
88    if version == "current":
89        return _FUTURE_API_LEVEL_INT
90
91    if _is_preview(version = version, platform_sdk_variables = platform_sdk_variables):
92        return _preview_codenames_to_ints(platform_sdk_variables).get(version) or int(version)
93
94    # Not preview nor current.
95    #
96    # If the level is the codename of an API level that has been finalized, this
97    # function returns the API level number associated with that API level. If
98    # the input is *not* a finalized codename, the input is returned unmodified.
99    canonical_level = api_levels_released_versions.get(version)
100    if not canonical_level:
101        if not version.isdigit():
102            fail("version %s could not be parsed as integer and is not a recognized codename" % version)
103        return int(version)
104    return canonical_level
105
106def _default_app_target_sdk_string(platform_sdk_variables):
107    if platform_sdk_variables.platform_sdk_final:
108        return str(platform_sdk_variables.platform_sdk_version)
109
110    if not platform_sdk_variables.platform_sdk_codename:
111        # soong returns NoneApiLevel here value: "(no version)", number: -1, isPreview: true
112        #
113        # fail fast instead of returning an arbitrary value.
114        fail("Platform_sdk_codename must be set.")
115
116    if platform_sdk_variables.platform_sdk_codename == "REL":
117        fail("Platform_sdk_codename should not be REL when Platform_sdk_final is false")
118
119    return platform_sdk_variables.platform_sdk_codename
120
121# Starlark implementation of DefaultAppTargetSDK from build/soong/android/config.go
122# https://cs.android.com/android/platform/superproject/+/master:build/soong/android/config.go;l=875-889;drc=b0dc477ef740ec959548fe5517bd92ac4ea0325c
123# check what you want returned for codename == "" case before using
124def _default_app_target_sdk(platform_sdk_variables):
125    """default_app_target_sdk returns the API level that platform apps are targeting.
126       This converts a codename to the exact ApiLevel it represents.
127    """
128    return _parse_api_level_from_version(
129        version = _default_app_target_sdk_string(platform_sdk_variables),
130        platform_sdk_variables = platform_sdk_variables,
131    )
132
133# Starlark implementation of EffectiveVersionString from build/soong/android/api_levels.go
134# EffectiveVersionString converts an api level string into the concrete version string that the module
135# should use. For modules targeting an unreleased SDK (meaning it does not yet have a number)
136# it returns the codename (P, Q, R, etc.)
137def _effective_version_string(
138        version,
139        platform_sdk_variables):
140    if not _is_preview(version, platform_sdk_variables):
141        return version
142    default_app_target_sdk_string = _default_app_target_sdk_string(platform_sdk_variables)
143    if not _is_preview(default_app_target_sdk_string, platform_sdk_variables):
144        return default_app_target_sdk_string
145    if version in platform_sdk_variables.platform_version_active_codenames:
146        return version
147    return default_app_target_sdk_string
148
149def api_from_product(platform_sdk_variables):
150    """Provides api level-related utility functions from platform variables.
151
152    Args:
153        platform_sdk_variables: a struct that must provides the 4
154          product variables: platform_sdk_final (boolean),
155          platform_sdk_version (int), platform_sdk_codename (string),
156          platform_version_active_codenames (string list)
157
158    Returns: A struct containing utility functions and constants
159        around api levels, e.g. for parsing them from user input and for
160        overriding them based on defaults and the input product variables.
161    """
162    return struct(
163        NONE_API_LEVEL = _NONE_API_LEVEL_INT,
164        FUTURE_API_LEVEL = _FUTURE_API_LEVEL_INT,
165        is_preview = lambda version: _is_preview(
166            version = version,
167            platform_sdk_variables = platform_sdk_variables,
168        ),
169        final_or_future = lambda version: _final_or_future(
170            version = version,
171            platform_sdk_variables = platform_sdk_variables,
172        ),
173        default_app_target_sdk_string = lambda: _default_app_target_sdk_string(platform_sdk_variables),
174        default_app_target_sdk = lambda: _default_app_target_sdk(platform_sdk_variables),
175        parse_api_level_from_version = lambda version: _parse_api_level_from_version(
176            version = version,
177            platform_sdk_variables = platform_sdk_variables,
178        ),
179        api_levels = _api_levels_with_previews(platform_sdk_variables),
180        effective_version_string = lambda version: _effective_version_string(
181            version = version,
182            platform_sdk_variables = platform_sdk_variables,
183        ),
184    )
185
186# TODO(b/300428335): access these variables in a transition friendly way.
187api = api_from_product(platform_versions)
188